MWCC/compiler_and_linker/unsorted/CExprConvMatch.c

2519 lines
81 KiB
C
Raw Normal View History

2022-12-29 12:32:55 +00:00
#include "compiler/CExpr.h"
2023-01-10 11:05:21 +00:00
#include "compiler/CABI.h"
#include "compiler/CClass.h"
#include "compiler/CDecl.h"
#include "compiler/CError.h"
#include "compiler/CInt64.h"
#include "compiler/CFunc.h"
#include "compiler/CMachine.h"
#include "compiler/CMangler.h"
#include "compiler/CObjC.h"
#include "compiler/CParser.h"
#include "compiler/CScope.h"
#include "compiler/CTemplateFunc.h"
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/objects.h"
#include "compiler/scopes.h"
#include "compiler/templates.h"
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct StandardConv {
Type *type1;
Type *type2;
UInt32 qual1;
UInt32 qual2;
Boolean x10; // unknown
Boolean x11;
Boolean x12;
Boolean x13;
Boolean x14;
Boolean x15;
} StandardConv;
typedef enum EImplicitConvType {
ICT_0,
ICT_1,
ICT_2,
ICT_3
} EImplicitConvType;
typedef struct ImplicitConv {
EImplicitConvType type;
union {
struct {
Object *x2;
StandardConv standardConv;
} ic2;
struct {
StandardConv standardConv;
} ic3;
} u;
} ImplicitConv;
typedef struct ConversionTypeList {
struct ConversionTypeList *next;
Object *func;
Type *type;
UInt32 qual;
} ConversionTypeList;
typedef struct Match {
struct Match *next;
Object *object;
Object *specialfunc;
Type *type;
UInt32 qual;
Type *type2;
UInt32 qual2;
ImplicitConv conv[3];
} Match;
#ifdef __MWERKS__
#pragma options align=reset
#endif
// forward decls
static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean flag2, Boolean flag3);
static Type *CExpr_GetImplictObjectParamType(Object *object, UInt32 *qual) {
Type *type;
CError_ASSERT(98, IS_TYPE_FUNC(object->type));
CError_ASSERT(99, TYPE_FUNC(object->type)->flags & FUNC_FLAGS_METHOD);
CError_ASSERT(100, !TYPE_METHOD(object->type)->x26);
CError_ASSERT(101, TYPE_METHOD(object->type)->args);
type = CDecl_NewRefPointerType(TYPE(TYPE_METHOD(object->type)->theclass));
*qual = TYPE_METHOD(object->type)->args->qual & Q_CV;
return type;
}
static Type *CExpr_GetParamType(Object *object, int index, UInt32 *qual) {
FuncArg *arg;
CError_ASSERT(120, IS_TYPE_FUNC(object->type));
CError_ASSERT(121, arg = TYPE_FUNC(object->type)->args);
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type)))
CError_ASSERT(125, arg = arg->next);
while (index > 0) {
CError_ASSERT(129, arg = arg->next);
index--;
}
*qual = arg->qual & Q_CV;
return arg->type;
}
static Boolean CExpr_HasNParams(Object *object, int count) {
FuncArg *arg;
int i;
CError_ASSERT(146, IS_TYPE_FUNC(object->type));
CError_ASSERT(147, arg = TYPE_FUNC(object->type)->args);
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type)))
arg = arg->next;
i = 0;
while (arg) {
arg = arg->next;
i++;
}
return i == count;
}
typedef enum TypeCompareMode {
TCM_0,
TCM_1,
TCM_2
} TypeCompareMode;
static Boolean CExpr_TypeCompare(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB, TypeCompareMode mode) {
if (typeA->type != typeB->type)
return 0;
switch (mode) {
case TCM_0:
while (1) {
switch (typeA->type) {
case TYPEPOINTER:
typeA = TPTR_TARGET(typeA);
typeB = TPTR_TARGET(typeB);
if (typeA->type != typeB->type)
return 0;
continue;
case TYPEMEMBERPOINTER:
if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2))
return 0;
typeA = TYPE_MEMBER_POINTER(typeA)->ty1;
typeB = TYPE_MEMBER_POINTER(typeB)->ty1;
if (typeA->type != typeB->type)
return 0;
continue;
}
break;
}
break;
case TCM_1:
switch (typeA->type) {
case TYPEPOINTER:
if ((qualA & Q_CV) != (qualB & Q_CV))
return 0;
typeA = TPTR_TARGET(typeA);
typeB = TPTR_TARGET(typeB);
break;
case TYPEMEMBERPOINTER:
if ((qualA & Q_CV) != (qualB & Q_CV))
return 0;
if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2))
return 0;
typeA = TYPE_MEMBER_POINTER(typeA)->ty1;
typeB = TYPE_MEMBER_POINTER(typeB)->ty1;
break;
}
break;
case TCM_2:
if ((qualA & Q_CV) != (qualB & Q_CV))
return 0;
break;
}
return is_typesame(typeA, typeB);
}
static int CExpr_IsReferenceCompatible(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB) {
if (CParser_IsSameOrMoreCVQualified(CParser_GetCVTypeQualifiers(typeA, qualA), CParser_GetCVTypeQualifiers(typeB, qualB))) {
if (CExpr_TypeCompare(typeA, qualA, typeB, qualB, TCM_1))
return 1;
if (IS_TYPE_CLASS(typeB) && IS_TYPE_CLASS(typeA)) {
short depth;
Boolean isambigbase;
if (CClass_GetBasePath(TYPE_CLASS(typeB), TYPE_CLASS(typeA), &depth, &isambigbase))
return 2;
}
}
return 0;
}
static Boolean CExpr_IsBaseOf(TypeClass *baseclass, TypeClass *superclass) {
ClassList *base;
for (base = superclass->bases; base; base = base->next) {
if (base->base == baseclass || CExpr_IsBaseOf(baseclass, base->base))
return 1;
}
return 0;
}
static Boolean CExpr_IsBetterClassConversion(TypeClass *a, TypeClass *b, TypeClass *c, TypeClass *d) {
if (a == c)
return CExpr_IsBaseOf(d, b);
if (b == d)
return CExpr_IsBaseOf(a, c);
return 0;
}
inline Boolean Inline_501D40(Type *a, Type *b) {
return (a == TYPE(&stbool)) && (IS_TYPE_POINTER_ONLY(b) || IS_TYPE_MEMBERPOINTER(b));
}
static Boolean CExpr_IsBetterStandardConv(StandardConv *a, StandardConv *b) {
Boolean flag10;
Boolean flag3;
flag10 = 1;
flag3 = 0;
if (b->x11) {
if (!a->x11)
flag3 = 1;
} else {
if (a->x11)
flag10 = 0;
}
if (b->x12) {
if (!a->x12)
flag3 = 1;
} else {
if (a->x12)
flag10 = 0;
}
if (b->x13) {
if (a->x13) {
if (Inline_501D40(b->type2, b->type1)) {
if (!Inline_501D40(a->type2, a->type1))
return 1;
} else {
if (Inline_501D40(a->type2, a->type1))
return 0;
}
} else {
flag3 = 1;
}
} else {
if (a->x13)
flag10 = 0;
}
if (flag10 && flag3)
return 1;
if (!a->x13) {
if (b->x13)
return 1;
if (a->x12) {
if (!b->x12)
return 0;
} else {
if (b->x12)
return 1;
}
} else {
if (!b->x13)
return 0;
}
if (
IS_TYPE_POINTER_ONLY(a->type1) &&
IS_TYPE_CLASS(TPTR_TARGET(a->type1)) &&
IS_TYPE_POINTER_ONLY(a->type2) &&
IS_TYPE_POINTER_ONLY(b->type1) &&
IS_TYPE_CLASS(TPTR_TARGET(b->type1)) &&
IS_TYPE_POINTER_ONLY(b->type2)
)
{
if (TPTR_TARGET(b->type2) == &stvoid) {
if (TPTR_TARGET(a->type2) == &stvoid) {
if (CExpr_IsBaseOf(TYPE_CLASS(TPTR_TARGET(a->type1)), TYPE_CLASS(TPTR_TARGET(b->type1))))
return 1;
} else {
if (TPTR_TARGET(a->type1) == TPTR_TARGET(b->type1) && IS_TYPE_CLASS(TPTR_TARGET(a->type2)))
return 1;
}
} else if (IS_TYPE_CLASS(TPTR_TARGET(a->type2)) && IS_TYPE_CLASS(TPTR_TARGET(b->type2))) {
if (CExpr_IsBetterClassConversion(
TYPE_CLASS(TPTR_TARGET(a->type1)),
TYPE_CLASS(TPTR_TARGET(a->type2)),
TYPE_CLASS(TPTR_TARGET(b->type1)),
TYPE_CLASS(TPTR_TARGET(b->type2))
))
return 1;
}
}
if (
IS_TYPE_CLASS(a->type1) &&
IS_TYPE_CLASS(a->type2) &&
IS_TYPE_CLASS(b->type1) &&
IS_TYPE_CLASS(b->type2) &&
CExpr_IsBetterClassConversion(
TYPE_CLASS(a->type1),
TYPE_CLASS(a->type2),
TYPE_CLASS(b->type1),
TYPE_CLASS(b->type2)
)
)
return 1;
if (
IS_TYPE_MEMBERPOINTER(a->type1) &&
IS_TYPE_MEMBERPOINTER(a->type2) &&
IS_TYPE_MEMBERPOINTER(b->type1) &&
IS_TYPE_MEMBERPOINTER(b->type2) &&
IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2) &&
IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2) &&
IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2) &&
IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2) &&
CExpr_IsBetterClassConversion(
TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2),
TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2),
TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2),
TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2)
)
)
return 1;
if (
a->x14 &&
b->x14 &&
CExpr_TypeCompare(a->type2, a->qual2, b->type2, b->qual2, TCM_1) &&
CParser_IsMoreCVQualified(
CParser_GetTypeQualifiers(b->type2, b->qual2),
CParser_GetTypeQualifiers(a->type2, a->qual2)
)
)
return 1;
return 0;
}
static Boolean CExpr_IsBetterImplicitConv(ImplicitConv *a, ImplicitConv *b) {
if (a->type > b->type)
return 1;
if (a->type != b->type)
return 0;
if (a->type == ICT_3)
return CExpr_IsBetterStandardConv(&a->u.ic3.standardConv, &b->u.ic3.standardConv);
if (a->type == ICT_2 && a->u.ic2.x2 == b->u.ic2.x2 && CExpr_IsBetterStandardConv(&a->u.ic2.standardConv, &b->u.ic2.standardConv))
return 1;
return 0;
}
typedef enum SSCRMode {
SSCR_0,
SSCR_1,
SSCR_2
} SSCRMode;
static Boolean CExpr_SetupStandardConversionResult(ENode *expr, Type *type2, UInt32 qual2, SSCRMode mode, Boolean x14, Boolean refFlag, StandardConv *result) {
UInt32 cv1;
UInt32 cv2;
if (x14) {
if (!CParser_IsConst(type2, qual2)) {
if (!refFlag && !CExpr_IsLValue(expr))
return 0;
if (mode != SSCR_0 && !IS_TYPE_CLASS(type2))
return 0;
}
cv2 = CParser_GetTypeQualifiers(type2, qual2) & Q_CV;
cv1 = CParser_GetTypeQualifiers(expr->rtype, ENODE_QUALS(expr)) & Q_CV;
if (cv2 != cv1 && !CParser_IsMoreCVQualified(cv2, cv1))
return 0;
}
memclrw(result, sizeof(StandardConv));
result->type2 = type2;
result->qual2 = qual2;
result->type1 = expr->rtype;
result->qual1 = ENODE_QUALS(expr);
result->x14 = x14;
switch (mode) {
case SSCR_0:
break;
case SSCR_1:
result->x12 = 1;
break;
case SSCR_2:
result->x13 = 1;
break;
default:
CError_FATAL(581);
}
return 1;
}
typedef enum MysteryEnum {
ME_0,
ME_1,
ME_255 = 255
} MysteryEnum;
inline MysteryEnum Inline_501FF0(UInt32 qual1, UInt32 qual2) {
if ((qual1 & Q_CV) == (qual2 & Q_CV))
return ME_0;
if (((qual2 & Q_CONST) && !(qual1 & Q_CONST)) || ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE)))
return ME_255;
return ME_1;
}
static Boolean CExpr_SetQualConversionResult(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, StandardConv *result) {
Boolean flag = 1;
UInt32 cv1;
UInt32 cv2;
while (1) {
cv1 = CParser_GetCVTypeQualifiers(type1, qual1);
cv2 = CParser_GetCVTypeQualifiers(type2, qual2);
switch (Inline_501FF0(cv1, cv2)) {
case ME_0:
break;
case ME_1:
result->x11 = 1;
if (!flag)
return 0;
break;
default:
return 0;
}
if (!(cv1 & Q_CONST))
flag = 0;
if (IS_TYPE_POINTER_ONLY(type1)) {
CError_ASSERT(635, IS_TYPE_POINTER_ONLY(type2));
type1 = TPTR_TARGET(type1);
type2 = TPTR_TARGET(type2);
} else {
if (!IS_TYPE_MEMBERPOINTER(type1))
return 1;
CError_ASSERT(642, IS_TYPE_MEMBERPOINTER(type2));
type1 = TYPE_MEMBER_POINTER(type1)->ty1;
type2 = TYPE_MEMBER_POINTER(type2)->ty1;
}
}
}
static Boolean CExpr_OverloadFuncMatch(NameSpaceObjectList *list, TemplArg *templargs, Type *type, ENode **outExpr) {
Object *object;
TemplFuncInstance *inst;
ENode *expr;
FuncArg *arg;
int i;
ObjectList *objlist;
Object *object26;
ObjectList *objlist25;
ObjectList *objlist24;
Boolean flag23;
if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(type = TPTR_TARGET(type)))
return 0;
object26 = NULL;
objlist25 = NULL;
objlist24 = NULL;
flag23 = 0;
while (list) {
object = OBJECT(list->object);
if (object->otype == OT_OBJECT) {
if (IS_TEMPL_FUNC(object->type)) {
if (!flag23 && CTempl_CanDeduceFunc(object, TYPE_FUNC(type), templargs)) {
CError_ASSERT(685, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0));
if (is_typesame(inst->object->type, type)) {
objlist = lalloc(sizeof(ObjectList));
objlist->next = objlist24;
objlist->object = object;
objlist24 = objlist;
if (object26 && object26 != inst->object) {
objlist = lalloc(sizeof(ObjectList));
objlist->next = objlist25;
objlist->object = inst->object;
objlist25 = objlist;
} else {
object26 = inst->object;
}
}
}
} else if (is_typesame(object->type, type)) {
if (object26 && flag23) {
Object *checkA, *checkB;
checkA = object;
if (checkA->datatype == DALIAS)
checkA = checkA->u.alias.object;
checkB = object26;
if (checkB->datatype == DALIAS)
checkB = checkB->u.alias.object;
if (checkA != checkB) {
objlist = lalloc(sizeof(ObjectList));
objlist->next = objlist25;
objlist->object = object;
objlist25 = objlist;
}
} else {
objlist25 = NULL;
object26 = object;
}
flag23 = 1;
}
}
list = list->next;
}
if (object26) {
if (outExpr) {
if (objlist25) {
i = 0;
for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next)
i++;
if (!flag23 && (object = CTempl_PartialOrdering(objlist24->object, objlist24->next, i))) {
CError_ASSERT(741, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0));
object26 = inst->object;
} else {
CError_OverloadedFunctionError(object26, objlist25);
}
}
expr = CExpr_MakeObjRefNode(object26, 1);
*outExpr = expr;
expr->rtype = CDecl_NewPointerType(object26->type);
expr->flags = object->qual & ENODE_FLAG_QUALS;
object26->flags |= OBJECT_FLAGS_UNUSED;
if (object26->datatype == DINLINEFUNC)
CError_Error(CErrorStr175);
}
return 1;
}
return 0;
}
static Boolean CExpr_StandardConversionMatch(ENode *expr, Type *type2, UInt32 qual2, Boolean x14, StandardConv *result) {
Type *type1;
UInt32 qual1;
Boolean refFlag;
Type *inner2;
Type *inner1;
SSCRMode mode;
NameSpaceObjectList list;
if (IS_TYPE_REFERENCE(type2)) {
type2 = TPTR_TARGET(type2);
if (IS_TYPE_POINTER_ONLY(type2))
expr = pointer_generation(expr);
refFlag = 1;
} else {
if (
(IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type2)) ||
(IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type2))
)
expr = pointer_generation(expr);
refFlag = 0;
}
type1 = expr->rtype;
qual1 = ENODE_QUALS(expr);
if (IS_TYPE_POINTER_ONLY(type2)) {
if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1)))
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
}
if (
IS_TYPE_INT(expr->rtype) &&
ENODE_IS_INDIRECT_TO(expr, EOBJREF) &&
(expr->data.monadic->data.objref->qual & Q_10000) &&
CInt64_IsZero(&expr->data.monadic->data.objref->u.data.u.intconst)
)
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
if (ENODE_IS(expr, EOBJLIST))
return CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type2, NULL) &&
CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) {
list.next = NULL;
list.object = OBJ_BASE(expr->data.objref);
return CExpr_OverloadFuncMatch(&list, NULL, type2, NULL) &&
CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
}
if (IS_TYPE_POINTER_ONLY(type1)) {
if (
ENODE_IS(expr, ESTRINGCONST) &&
TPTR_TARGET(type2) == TPTR_TARGET(type1) &&
!(qual2 & Q_CONST) &&
(
TPTR_TARGET(type2) == TYPE(&stchar) ||
TPTR_TARGET(type2) == TYPE(&stunsignedchar) ||
TPTR_TARGET(type2) == CParser_GetWCharType()
)
)
{
if (
CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result) &&
CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1 & ~Q_CONST, result)
)
{
result->x11 = 1;
return 1;
} else {
return 0;
}
}
if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type2))
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
if (IS_TYPE_VOID(TPTR_TARGET(type2)) || (!copts.cplusplus && IS_TYPE_VOID(TPTR_TARGET(type1)))) {
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, IS_TYPE_VOID(TPTR_TARGET(type1)) ? SSCR_0 : SSCR_2, refFlag, x14, result)) {
switch (Inline_501FF0(qual2, CParser_GetCVTypeQualifiers(TPTR_TARGET(type1), qual1))) {
case ME_1:
result->x11 = 1;
case ME_0:
return 1;
default:
return 0;
}
} else {
return 0;
}
}
inner2 = TPTR_TARGET(type2);
inner1 = TPTR_TARGET(type1);
while (1) {
if (inner2->type != inner1->type)
break;
switch (inner2->type) {
case TYPEPOINTER:
inner2 = TPTR_TARGET(inner2);
inner1 = TPTR_TARGET(inner1);
continue;
case TYPEMEMBERPOINTER:
if (!is_typesame(TYPE_MEMBER_POINTER(inner2)->ty2, TYPE_MEMBER_POINTER(inner1)->ty2))
break;
inner2 = TYPE_MEMBER_POINTER(inner2)->ty1;
inner1 = TYPE_MEMBER_POINTER(inner1)->ty1;
if (!IS_TYPE_POINTER_ONLY(inner2) && !IS_TYPE_MEMBERPOINTER(inner2)) {
if (!is_memberpointerequal(inner2, inner1))
break;
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result))
return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
else
return 0;
}
continue;
default:
if (!is_typesame(inner2, inner1))
break;
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result))
return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
else
return 0;
}
break;
}
if (IS_TYPE_CLASS(TPTR_TARGET(type2)) && IS_TYPE_CLASS(TPTR_TARGET(type1))) {
short depth;
Boolean isambigbase;
if (CClass_GetBasePath(TYPE_CLASS(TPTR_TARGET(type1)), TYPE_CLASS(TPTR_TARGET(type2)), &depth, &isambigbase)) {
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
else
return 0;
}
}
}
if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_POINTER_ONLY(type1)) {
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
return 1;
}
return 0;
}
if (is_typesame(type2, type1))
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
if (type2 == TYPE(&stbool)) {
switch (type1->type) {
case TYPEINT:
case TYPEFLOAT:
case TYPEENUM:
case TYPEMEMBERPOINTER:
case TYPEPOINTER:
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result);
default:
return 0;
}
}
if (IS_TYPE_MEMBERPOINTER(type2)) {
if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1)))
return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result);
}
if (ENODE_IS(expr, EMEMBER)) {
expr = getpointertomemberfunc(expr, type2, 0);
type1 = expr->rtype;
}
if (IS_TYPE_MEMBERPOINTER(type1)) {
short depth;
Boolean isambigbase;
CError_ASSERT(996, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2) && IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2));
if (!is_memberpointerequal(TYPE_MEMBER_POINTER(type2)->ty1, TYPE_MEMBER_POINTER(type1)->ty1))
return 0;
if (
TYPE_MEMBER_POINTER(type2)->ty2 == TYPE_MEMBER_POINTER(type1)->ty2 ||
CClass_GetBasePath(TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2), &depth, &isambigbase)
)
{
if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
return CExpr_SetQualConversionResult(TYPE_MEMBER_POINTER(type2)->ty1, qual2, TYPE_MEMBER_POINTER(type1)->ty1, qual1, result);
else
return 0;
}
}
return 0;
}
mode = SSCR_2;
switch (type1->type) {
case TYPEINT:
switch (type2->type) {
case TYPEINT:
if (TYPE_INTEGRAL(type1)->integral < IT_INT) {
if (type2 == TYPE(&stsignedint)) {
if (type1->size < type2->size || !is_unsigned(type1))
mode = SSCR_1;
} else if (type2 == TYPE(&stunsignedint)) {
if (type2->size == type1->size && is_unsigned(type1))
mode = SSCR_1;
}
}
break;
case TYPEFLOAT:
break;
case TYPEENUM:
if (copts.cplusplus)
return 0;
break;
default:
return 0;
}
break;
case TYPEFLOAT:
switch (type2->type) {
case TYPEINT:
break;
case TYPEFLOAT:
if (type2 == TYPE(&stdouble)) {
if (type1 == TYPE(&stfloat) || type1 == TYPE(&stshortdouble))
mode = SSCR_1;
}
break;
case TYPEENUM:
if (copts.cplusplus)
return 0;
break;
default:
return 0;
}
break;
case TYPEENUM:
switch (type2->type) {
case TYPEINT:
if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) {
if (type1->size == type2->size && is_unsigned(TYPE_ENUM(type1)->enumtype)) {
if (type2 == TYPE(&stunsignedint))
mode = SSCR_1;
} else {
if (type2 == TYPE(&stsignedint))
mode = SSCR_1;
}
} else {
if (TYPE_ENUM(type1)->enumtype == type2)
mode = SSCR_1;
}
break;
case TYPEFLOAT:
break;
case TYPEENUM:
if (copts.cplusplus)
return 0;
break;
default:
return 0;
}
break;
case TYPECLASS: {
short depth;
Boolean isambigbase;
if (!IS_TYPE_CLASS(type1) || !CClass_GetBasePath(TYPE_CLASS(type1), TYPE_CLASS(type2), &depth, &isambigbase))
return 0;
break;
}
default:
return 0;
}
return CExpr_SetupStandardConversionResult(expr, type2, qual2, mode, refFlag, x14, result);
}
static ENode *CExpr_UserConversion(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result, Boolean flag1, Boolean isExplicit, Boolean flag3) {
Object *object28;
Object *object27;
Object *object26;
ObjectList *objlist25;
ObjectList *objlist24;
ObjectList *objlist;
TypeFunc *tfunc23;
Type *tmptype23;
NameSpaceObjectList *list22;
Boolean flag22;
Boolean flag21;
FuncArg *arg21;
Boolean flag20;
ENode *newExpr;
ENode *funcref;
ENode *tmpExpr;
ENodeList *arglist;
UInt32 q1;
UInt32 q2;
StandardConv sc3;
StandardConv sc2;
StandardConv sc1;
ConversionIterator convIter;
ENodeList myarglist;
ObjectList myobjlist;
BClassList path;
object28 = NULL;
object27 = NULL;
objlist25 = NULL;
objlist24 = NULL;
if (type2->size == 0)
CDecl_CompleteType(type2);
if (expr->rtype->size == 0)
CDecl_CompleteType(expr->rtype);
if (IS_TYPE_CLASS(expr->rtype)) {
CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype));
flag22 = 1;
while ((object26 = CExpr_ConversionIteratorNext(&convIter))) {
tfunc23 = TYPE_FUNC(object26->type);
if (tfunc23->flags & FUNC_FLAGS_100000) {
object26 = CTempl_DeduceFromConversion(object26, type2, qual2);
if (!object26)
continue;
tfunc23 = TYPE_FUNC(object26->type);
}
if (flag3) {
if (
!IS_TYPE_REFERENCE(tfunc23->functype) ||
!CExpr_IsReferenceCompatible(type2, qual2, TPTR_TARGET(tfunc23->functype), tfunc23->qual)
)
continue;
}
CError_ASSERT(1230, tfunc23->args && IS_TYPE_POINTER_ONLY(tfunc23->args->type));
q1 = ENODE_QUALS(expr);
q2 = tfunc23->args->qual;
if ((q1 & Q_CV) != (q2 & Q_CV)) {
if (!flag22)
continue;
if ((q1 & Q_CONST) && !(q2 & Q_CONST))
continue;
if ((q1 & Q_VOLATILE) && !(q2 & Q_VOLATILE))
continue;
flag21 = 1;
} else {
flag21 = 0;
}
newExpr = CExpr_NewENode(ETEMP);
newExpr->rtype = tfunc23->functype;
newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS;
flag20 = 0;
if (IS_TYPE_REFERENCE(newExpr->rtype)) {
newExpr->rtype = TPTR_TARGET(newExpr->rtype);
if (!CParser_IsConst(newExpr->rtype, tfunc23->qual)) {
newExpr = makemonadicnode(newExpr, EINDIRECT);
newExpr->data.monadic->rtype = TYPE(&void_ptr);
newExpr = makemonadicnode(newExpr, EINDIRECT);
newExpr->data.monadic->rtype = TYPE(&void_ptr);
flag20 = 1;
}
}
if (CExpr_StandardConversionMatch(newExpr, type2, qual2, 0, &sc1)) {
if (flag22 && !flag21) {
object28 = NULL;
objlist25 = NULL;
flag22 = 0;
}
if (object28 && object28 != object26) {
if (CExpr_IsBetterStandardConv(&sc3, &sc1))
continue;
if (!CExpr_IsBetterStandardConv(&sc1, &sc3)) {
objlist = lalloc(sizeof(ObjectList));
objlist->next = objlist25;
objlist->object = object28;
objlist25 = objlist;
} else {
objlist25 = NULL;
}
}
object28 = object26;
sc3 = sc1;
sc3.x15 = flag20;
}
}
}
if (!flag3 && IS_TYPE_CLASS(type2) && (list22 = CClass_Constructor(TYPE_CLASS(type2)))) {
for (; list22; list22 = list22->next) {
object26 = OBJECT(list22->object);
if (
object26->otype == OT_OBJECT &&
IS_TYPE_FUNC(tfunc23 = TYPE_FUNC(object26->type)) &&
(isExplicit || !(object26->qual & Q_EXPLICIT))
)
{
if (tfunc23->flags & FUNC_FLAGS_100000) {
myarglist.next = NULL;
myarglist.node = expr;
object26 = CTempl_DeduceFromFunctionCall(object26, NULL, &myarglist);
if (!object26)
continue;
tfunc23 = TYPE_FUNC(object26->type);
}
if (!(arg21 = tfunc23->args))
continue;
if (!(arg21 = arg21->next))
continue;
if ((TYPE_CLASS(type2)->flags & CLASS_FLAGS_20) && !(arg21 = arg21->next))
continue;
if (arg21 == &elipsis)
continue;
if (arg21->next && !arg21->next->dexpr && arg21->next != &elipsis)
continue;
tmptype23 = arg21->type;
if (IS_TYPE_REFERENCE(tmptype23)) {
tmptype23 = TPTR_TARGET(tmptype23);
if (!CParser_IsConst(tmptype23, arg21->qual) && !CExpr_IsLValue(expr))
continue;
}
if (CExpr_StandardConversionMatch(expr, tmptype23, arg21->qual, 0, &sc1)) {
if (object27) {
if (!object26->u.func.inst && !object27->u.func.inst)
continue;
if (CExpr_IsBetterStandardConv(&sc2, &sc1))
continue;
if (!CExpr_IsBetterStandardConv(&sc1, &sc2)) {
if (!object26->u.func.inst && object27->u.func.inst) {
objlist24 = NULL;
} else {
objlist = lalloc(sizeof(ObjectList));
objlist->next = objlist25;
objlist->object = object28;
objlist25 = objlist;
}
} else {
objlist25 = NULL;
}
}
object27 = object26;
sc2 = sc1;
}
}
}
}
if (object28 && object27) {
if (!CExpr_IsBetterStandardConv(&sc2, &sc3)) {
if (!CExpr_IsBetterStandardConv(&sc3, &sc2)) {
if (result) {
result->type = ICT_2;
result->u.ic2.x2 = object28;
result->u.ic2.standardConv = sc3;
}
if (flag1) {
myobjlist.next = NULL;
myobjlist.object = object27;
CError_OverloadedFunctionError(object28, &myobjlist);
}
} else {
object27 = NULL;
}
} else {
object28 = NULL;
}
}
if (object28) {
if (result) {
result->type = ICT_2;
result->u.ic2.x2 = object28;
result->u.ic2.standardConv = sc3;
}
if (!flag1)
return expr;
if (objlist25)
CError_OverloadedFunctionError(object28, objlist25);
tfunc23 = TYPE_FUNC(object28->type);
CError_ASSERT(1416, IS_TYPEFUNC_METHOD(tfunc23));
funcref = create_objectrefnode(object28);
object28->flags |= OBJECT_FLAGS_UNUSED;
arglist = lalloc(sizeof(ENodeList));
arglist->next = NULL;
expr = getnodeaddress(expr, 0);
arglist->node = CExpr_AssignmentPromotion(
expr,
CDecl_NewPointerType(TYPE(TYPE_METHOD(tfunc23)->theclass)),
expr->flags,
0);
newExpr = lalloc(sizeof(ENode));
newExpr->type = EFUNCCALL;
newExpr->cost = 4;
newExpr->rtype = tfunc23->functype;
newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS;
newExpr->data.funccall.funcref = funcref;
newExpr->data.funccall.args = arglist;
newExpr->data.funccall.functype = TYPE_FUNC(object28->type);
newExpr = CExpr_AdjustFunctionCall(newExpr);
newExpr = checkreference(newExpr);
if (newExpr->rtype != type2) {
if (flag3) {
tmpExpr = CExpr_DerivedToBase(newExpr, type2, qual2, 1, 0, 1);
if (tmpExpr)
return tmpExpr;
}
newExpr = CExpr_Convert(newExpr, type2, qual2, 0, 1);
}
return newExpr;
}
if (object27) {
if (result) {
result->type = ICT_2;
result->u.ic2.x2 = object27;
result->u.ic2.standardConv = sc2;
}
if (!flag1)
return expr;
if (objlist24)
CError_OverloadedFunctionError(object27, objlist24);
arglist = lalloc(sizeof(ENodeList));
arglist->next = NULL;
arglist->node = expr;
if (TYPE_CLASS(type2)->flags & CLASS_FLAGS_20) {
arglist->next = lalloc(sizeof(ENodeList));
arglist->next->node = expr;
arglist->next->next = NULL;
arglist->node = intconstnode(TYPE(&stsignedshort), 1);
}
path.next = NULL;
path.type = type2;
tmpExpr = makemonadicnode(create_temp_node(type2), EINDIRECT);
tmpExpr->rtype = type2;
newExpr = CExpr_GenericFuncCall(
&path, tmpExpr, 0, object27, NULL, NULL, arglist, 0, 0, 1
);
if (ENODE_IS2(newExpr, EFUNCCALL, EFUNCCALLP)) {
newExpr->rtype = CDecl_NewPointerType(type2);
newExpr = makemonadicnode(newExpr, EINDIRECT);
newExpr->rtype = type2;
}
return newExpr;
}
return NULL;
}
static Boolean CExpr_UserConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) {
Boolean flag;
if (IS_TYPE_REFERENCE(type2)) {
type2 = TPTR_TARGET(type2);
flag = !CParser_IsConst(type2, qual2);
} else {
expr = pointer_generation(expr);
flag = 0;
}
if (CExpr_UserConversion(expr, type2, qual2, result, 0, 0, flag))
return 1;
return 0;
}
static Boolean CExpr_ImplicitConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) {
if (CExpr_StandardConversionMatch(expr, type2, qual2, 0, &result->u.ic3.standardConv)) {
result->type = ICT_3;
return 1;
}
if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2) || (IS_TYPE_REFERENCE(type2) && IS_TYPE_CLASS(TPTR_TARGET(type2)))) {
if (CExpr_UserConversionMatch(expr, type2, qual2, result)) {
result->type = ICT_2;
return 1;
}
}
return 0;
}
Boolean CExpr_CanImplicitlyConvert(ENode *expr, Type *type2, UInt32 qual2) {
ImplicitConv result;
return CExpr_ImplicitConversionMatch(expr, type2, qual2, &result);
}
static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean nullcheckflag, Boolean pathcheckflag) {
BClassList *path;
short depth;
Boolean isambigbase;
if (
IS_TYPE_CLASS(type2) &&
IS_TYPE_CLASS(expr->rtype) &&
(path = CClass_GetBasePath(TYPE_CLASS(expr->rtype), TYPE_CLASS(type2), &depth, &isambigbase))
)
{
if (isambigbase)
CError_Error(CErrorStr188);
if (flag1)
CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
if (pathcheckflag) {
expr = getnodeaddress(expr, 0);
expr = makemonadicnode(CExpr_ClassPointerCast(path, expr, nullcheckflag), EINDIRECT);
expr->rtype = type2;
expr->flags = qual2 & ENODE_FLAG_QUALS;
}
return expr;
}
else {
return NULL;
}
}
static ENode *CExpr_ClassReferenceConversion(ENode *expr, Type *type2, UInt32 qual2, Boolean pathcheckflag) {
int refcompat;
if (CExpr_IsLValue(expr) && IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) {
refcompat = CExpr_IsReferenceCompatible(type2, 0, expr->rtype, 0);
if (refcompat > 0) {
if (refcompat == 2) {
CError_ASSERT(1668, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype));
expr = CExpr_DerivedToBase(expr, type2, qual2, pathcheckflag, 0, 1);
}
expr->flags = qual2 & ENODE_FLAG_QUALS;
return expr;
}
refcompat = CExpr_IsReferenceCompatible(expr->rtype, 0, type2, 0);
if (refcompat > 0) {
expr = CClass_ClassPointerCast(
getnodeaddress(expr, 0),
TYPE_CLASS(expr->rtype), TYPE_CLASS(type2),
1, 1, pathcheckflag
);
CError_ASSERT(1680, IS_TYPE_POINTER_ONLY(expr->rtype));
expr = makemonadicnode(expr, EINDIRECT);
expr->rtype = type2;
expr->flags = qual2 & ENODE_FLAG_QUALS;
return expr;
}
}
if (IS_TYPE_CLASS(expr->rtype)) {
if ((expr = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1)))
return expr;
}
return NULL;
}
static ENode *CExpr_BindToReference(ENode *expr, Type *type2, UInt32 qual2) {
UInt32 cv;
int refcompat;
ENode *tmp;
cv = CParser_GetCVTypeQualifiers(type2, qual2);
if (CExpr_IsLValue(expr)) {
refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr));
if (refcompat > 0) {
if (refcompat == 2) {
CError_ASSERT(1718, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype));
expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1);
}
return getnodeaddress(expr, 0);
}
} else if (IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) {
refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr));
if (refcompat > 0) {
if (refcompat == 2)
expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1);
return getnodeaddress(expr, 0);
}
}
if (IS_TYPE_CLASS(expr->rtype)) {
if ((tmp = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1)))
return getnodeaddress(tmp, 0);
}
if (!(cv & Q_CONST))
CError_Error(CErrorStr228);
if (cv & Q_VOLATILE)
CError_Error(CErrorStr259);
if (expr->rtype != type2)
expr = CExpr_Convert(expr, type2, qual2, 0, 1);
if (!CExpr_IsLValue(expr)) {
expr = CExpr_LValue(expr, 0, 0);
if (!ENODE_IS(expr, EINDIRECT))
expr = get_address_of_temp_copy(expr, 1);
else
expr = getnodeaddress(expr, 0);
} else {
expr = getnodeaddress(expr, 0);
}
return expr;
}
ENode *CExpr_Convert(ENode *expr, Type *type, UInt32 qual, Boolean isExplicit, Boolean flag2) {
UInt32 cv;
ENode *refExpr;
ENode *newExpr;
Type *typeCopy;
NameSpaceObjectList myList;
cv = qual & Q_CV;
if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) {
expr = CExpr_RewriteConst(expr);
expr->rtype = type;
expr->flags &= ~ENODE_FLAG_QUALS;
expr->flags |= cv;
return expr;
}
if (type == TYPE(&stvoid)) {
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
}
if (IS_TYPE_REFERENCE(type)) {
if (isExplicit) {
refExpr = CExpr_ClassReferenceConversion(expr, TPTR_TARGET(type), qual, flag2);
if (refExpr)
return refExpr;
expr = getnodeaddress(expr, 0);
typeCopy = galloc(sizeof(TypePointer));
*TYPE_POINTER(typeCopy) = *TYPE_POINTER(type);
TPTR_QUAL(typeCopy) &= ~Q_REFERENCE;
expr = CExpr_Convert(expr, typeCopy, qual, 0, flag2);
expr = makemonadicnode(expr, EINDIRECT);
expr->rtype = TPTR_TARGET(type);
expr->flags = cv;
return expr;
} else {
return CExpr_BindToReference(expr, TPTR_TARGET(type), qual);
}
}
if (
(IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type)) ||
(IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type))
)
{
expr = pointer_generation(expr);
} else {
expr = CExpr_RewriteConst(expr);
}
if (ENODE_IS(expr, EOBJLIST)) {
if (CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type, &refExpr))
return refExpr;
} else if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) {
myList.next = NULL;
myList.object = OBJ_BASE(expr->data.objref);
if (CExpr_OverloadFuncMatch(&myList, NULL, type, &refExpr))
return refExpr;
} else if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) {
if (expr->rtype->size == 0)
CDecl_CompleteType(expr->rtype);
if (IS_TYPE_CLASS(type)) {
CanAllocObject(type);
if (!CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_IsTrivialCopyClass(TYPE_CLASS(type))) {
if (expr->rtype == type)
return expr;
refExpr = CExpr_DerivedToBase(expr, type, qual, flag2, 0, 1);
if (refExpr)
return refExpr;
}
}
refExpr = CExpr_UserConversion(expr, type, qual, NULL, 1, isExplicit, 0);
if (refExpr) {
refExpr->flags = cv;
return refExpr;
}
} else if (!isExplicit && is_typesame(expr->rtype, type)) {
if (ENODE_IS(expr, EINDIRECT) && ENODE_QUALS(expr) != cv)
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
} else {
if (
copts.warn_implicitconv &&
!isExplicit &&
IS_TYPE_INT_OR_FLOAT(type) &&
IS_TYPE_INT_OR_FLOAT(expr->rtype)
)
CExpr_CheckArithmConversion(expr, type);
switch (type->type) {
case TYPEINT:
if (type == TYPE(&stbool)) {
switch (expr->rtype->type) {
case TYPEINT:
case TYPEFLOAT:
case TYPEENUM:
case TYPEMEMBERPOINTER:
case TYPEPOINTER:
return CExpr_ConvertToBool(expr, isExplicit);
}
} else {
switch (expr->rtype->type) {
case TYPEENUM:
expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
case TYPEINT:
case TYPEFLOAT:
do_int_float_conversion:
if (
ENODE_IS(expr, ETYPCON) &&
expr->rtype->type == type->type &&
expr->rtype->size == type->size &&
is_unsigned(expr->rtype) == is_unsigned(type) &&
ENODE_QUALS(expr) == qual
)
{
expr->rtype = type;
expr->flags |= ENODE_FLAG_80;
return expr;
} else {
refExpr = promote(expr, type);
refExpr->flags = cv;
return refExpr;
}
break;
case TYPEPOINTER:
if (expr->rtype->size > type->size && copts.warn_ptr_int_conv)
CError_Warning(CErrorStr382);
if (ENODE_IS(expr, ETYPCON)) {
ENode *inner = expr->data.monadic;
if (ENODE_IS(inner, EINTCONST)) {
inner->rtype = type;
inner->flags = cv;
inner->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), inner->data.intval);
return inner;
}
}
if (type->size != 4) {
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = TYPE(&stunsignedlong);
}
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
}
}
break;
case TYPEFLOAT:
switch (expr->rtype->type) {
case TYPEENUM:
expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
case TYPEINT:
case TYPEFLOAT:
goto do_int_float_conversion;
}
break;
case TYPEENUM:
expr = CExpr_Convert(expr, TYPE_ENUM(type)->enumtype, qual, isExplicit, flag2);
if (!ENODE_IS(expr, EINTCONST))
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
case TYPEPOINTER:
switch (expr->rtype->type) {
case TYPEENUM:
expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
case TYPEINT:
if (expr->rtype->size != 4) {
if (!ENODE_IS(expr, EINTCONST))
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = TYPE(&stunsignedlong);
}
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
case TYPEPOINTER:
if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type)))
expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, flag2);
if (!ENODE_IS(expr, ETYPCON))
expr = makemonadicnode(expr, ETYPCON);
expr->rtype = type;
expr->flags = cv;
return expr;
}
break;
case TYPEMEMBERPOINTER:
if (!IS_TYPE_MEMBERPOINTER(expr->rtype))
expr = CExpr_MemberPointerConversion(expr, TYPE_MEMBER_POINTER(type), 1);
if (IS_TYPE_MEMBERPOINTER(expr->rtype)) {
expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), TYPE_MEMBER_POINTER(type), flag2);
expr->flags = cv;
return expr;
}
break;
}
}
if (isExplicit) {
if ((newExpr = CodeGen_HandleTypeCast(expr, type, qual)))
return newExpr;
}
CError_Error(
isExplicit ? CErrorStr247 : CErrorStr209,
expr->rtype, ENODE_QUALS(expr),
type, qual);
return nullnode();
}
ENode *CExpr_AssignmentPromotion(ENode *expr, Type *type2, UInt32 qual2, Boolean flag) {
ImplicitConv result;
if (copts.old_argmatch)
return oldassignmentpromotion(expr, type2, qual2, flag);
if (ENODE_IS(expr, EMEMBER))
expr = getpointertomemberfunc(expr, type2, 1);
if (!CExpr_ImplicitConversionMatch(expr, type2, qual2, &result)) {
CError_Error(CErrorStr209, expr->rtype, ENODE_QUALS(expr), type2, qual2);
return nullnode();
}
return CExpr_Convert(expr, type2, qual2, 0, flag);
}
static Boolean CExpr_IsBetterMatch(Match *a, Match *b, int count) {
ImplicitConv *convA;
ImplicitConv *convB;
int i;
Boolean flag;
convA = a->conv;
convB = b->conv;
flag = 0;
if (convA->type != ICT_0 && convB->type != ICT_0) {
if (CExpr_IsBetterImplicitConv(convB, convA))
return 0;
if (CExpr_IsBetterImplicitConv(convA, convB))
flag = 1;
}
for (i = 0; i < count; i++) {
if (CExpr_IsBetterImplicitConv(++convB, ++convA))
return 0;
if (CExpr_IsBetterImplicitConv(convA, convB))
flag = 1;
}
if (flag)
return 1;
if (b->object) {
CError_ASSERT(2165, IS_TYPE_FUNC(b->object->type));
if (b->object->u.func.inst) {
if (!a->object)
return 1;
CError_ASSERT(2169, IS_TYPE_FUNC(a->object->type));
if (!a->object->u.func.inst)
return 1;
CError_ASSERT(2174, a->specialfunc && b->specialfunc);
if (CTempl_FuncIsMoreSpecialized(a->specialfunc, b->specialfunc))
return 1;
}
}
return 0;
}
static Boolean CExpr_MatchArgs(Object *func, ENodeList *argexprs, ENode *expr, ImplicitConv *convs) {
FuncArg *args;
ENode *newExpr;
Type *type;
args = TYPE_FUNC(func->type)->args;
if (!(TYPE_FUNC(func->type)->flags & FUNC_FLAGS_METHOD)) {
convs->type = ICT_0;
} else if (TYPE_METHOD(func->type)->x26) {
convs->type = ICT_0;
} else if (TYPE_FUNC(func->type)->flags & FUNC_FLAGS_1000) {
convs->type = ICT_0;
args = args->next;
} else {
if (!expr)
return 0;
newExpr = lalloc(sizeof(ENode));
newExpr->type = EINTCONST;
newExpr->cost = 0;
newExpr->flags = expr->flags;
newExpr->rtype = CDecl_NewPointerType(expr->rtype);
newExpr->data.intval = cint64_zero;
if (func->datatype == DALIAS) {
CError_ASSERT(2231, func->u.alias.member);
type = CDecl_NewPointerType(func->u.alias.member->type);
} else {
type = args->type;
}
if (!CExpr_ImplicitConversionMatch(newExpr, type, args->qual, convs))
return 0;
args = args->next;
}
convs++;
while (1) {
if (!args || args->type == &stvoid) {
if (argexprs)
return 0;
else
return 1;
}
if (args == &elipsis || args == &oldstyle) {
while (argexprs) {
convs->type = ICT_1;
argexprs = argexprs->next;
convs++;
}
return 1;
}
if (!argexprs)
return args->dexpr != NULL;
if (!CExpr_ImplicitConversionMatch(argexprs->node, args->type, args->qual, convs))
return 0;
argexprs = argexprs->next;
args = args->next;
convs++;
}
}
static Object *CExpr_GetMatchObject(Match *match, HashNameNode *name) {
Object *object;
FuncArg *arg;
TypeFunc *tfunc;
if (match->object)
return match->object;
tfunc = lalloc(sizeof(TypeFunc));
memclrw(tfunc, sizeof(TypeFunc));
tfunc->type = TYPEFUNC;
tfunc->functype = &stvoid;
arg = lalloc(sizeof(FuncArg));
memclrw(arg, sizeof(FuncArg));
arg->type = match->type;
arg->qual = match->qual;
tfunc->args = arg;
if (match->type2) {
arg = lalloc(sizeof(FuncArg));
memclrw(arg, sizeof(FuncArg));
arg->type = match->type2;
arg->qual = match->qual2;
tfunc->args->next = arg;
}
object = lalloc(sizeof(Object));
memclrw(object, sizeof(Object));
object->name = name;
object->datatype = DFUNC;
object->nspace = cscope_root;
object->type = TYPE(tfunc);
return object;
}
static Match *CExpr_FindBestMatch(Match *matches, int count, HashNameNode *name, ObjectList **outList, ENodeList *argExprs) {
Match *scan;
Match *best;
ObjectList *listHead;
ObjectList *list;
best = matches;
for (scan = matches->next; scan; scan = scan->next) {
if (CExpr_IsBetterMatch(scan, best, count))
best = scan;
}
for (scan = matches, listHead = NULL; scan; scan = scan->next) {
if (scan != best && !CExpr_IsBetterMatch(best, scan, count)) {
list = lalloc(sizeof(ObjectList));
list->next = listHead;
list->object = CExpr_GetMatchObject(scan, name);
listHead = list;
}
}
if (!outList) {
if (listHead)
CError_OverloadedFunctionError(CExpr_GetMatchObject(best, name), listHead);
} else {
*outList = listHead;
}
return best;
}
void CExpr_FuncArgMatch(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match13, ENode *expr, Boolean flag) {
NameSpaceObjectList *i;
NameSpaceObjectList *j;
Match *match;
Match *matches;
Object *object;
Object *object2;
Object *specialfunc;
ENodeList *argscan;
int argcount;
for (argscan = argexprs, argcount = 0; argscan; argscan = argscan->next) {
CDecl_CompleteType(argscan->node->rtype);
argcount++;
}
matches = NULL;
match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv)));
for (i = list; i; i = i->next) {
object = OBJECT(i->object);
if (
object->otype == OT_OBJECT &&
IS_TYPE_FUNC(object->type) &&
(!flag || !(object->qual & Q_EXPLICIT))
)
{
if (object->datatype == DALIAS && (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_METHOD)) {
for (j = list; j; j = j->next) {
if (j == i)
continue;
object2 = OBJECT(j->object);
if (
object2->otype == OT_OBJECT &&
IS_TYPE_METHOD(object2->type) &&
(TYPE_FUNC(object2->type)->flags & FUNC_FLAGS_CV) == (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_CV)
)
{
FuncArg *argsA;
FuncArg *argsB;
argsA = TYPE_FUNC(object->type)->args;
if (argsA && !TYPE_METHOD(object->type)->x26)
argsA = argsA->next;
argsB = TYPE_FUNC(object2->type)->args;
if (argsB && !TYPE_METHOD(object2->type)->x26)
argsB = argsB->next;
if (is_arglistsame(argsA, argsB))
break;
}
}
if (j)
continue;
}
if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000) {
specialfunc = object;
object = CTempl_DeduceFromFunctionCall(object, templargs, argexprs);
if (!object)
continue;
} else {
if (templargs)
continue;
specialfunc = NULL;
}
if (CExpr_MatchArgs(object, argexprs, expr, match->conv)) {
match->object = object;
match->specialfunc = specialfunc;
match->next = matches;
matches = match;
match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv)));
}
}
}
if (matches) {
matches = CExpr_FindBestMatch(matches, argcount, NULL, &match13->list, argexprs);
match13->obj = matches->object;
}
}
static ConversionTypeList *CExpr_BuildConversionTypeList(ENode *expr) {
ConversionTypeList *first;
ConversionTypeList *list;
Object *object;
Type *type;
ConversionIterator convIter;
if (!IS_TYPE_CLASS(expr->rtype)) {
first = lalloc(sizeof(ConversionTypeList));
first->next = NULL;
first->func = NULL;
first->type = expr->rtype;
first->qual = ENODE_QUALS(expr);
if (IS_TYPE_ENUM(first->type))
first->qual = 0;
} else {
first = NULL;
CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype));
while ((object = CExpr_ConversionIteratorNext(&convIter))) {
type = TYPE_FUNC(object->type)->functype;
if (IS_TYPE_REFERENCE(type))
type = TPTR_TARGET(type);
if (!IS_TYPE_CLASS(type)) {
list = lalloc(sizeof(ConversionTypeList));
list->next = first;
list->func = object;
list->type = type;
list->qual = TYPE_FUNC(object->type)->qual & Q_CV;
first = list;
}
}
}
return first;
}
static Type *CExpr_NextPromotedIntegralType(int *p) {
switch (++(*p)) {
case 1: return TYPE(&stsignedint);
case 2: return TYPE(&stunsignedint);
case 3: return TYPE(&stsignedlong);
case 4: return TYPE(&stunsignedlong);
case 5:
if (copts.longlong)
return TYPE(&stsignedlonglong);
else
return NULL;
case 6:
if (copts.longlong)
return TYPE(&stunsignedlonglong);
else
return NULL;
}
return NULL;
}
static Type *CExpr_NextArithmeticType(int *p) {
switch (++(*p)) {
case 1: return TYPE(&stbool);
case 2: return TYPE(&stchar);
case 3: return TYPE(&stsignedchar);
case 4: return TYPE(&stunsignedchar);
case 5: return TYPE(&stwchar);
case 6: return TYPE(&stsignedshort);
case 7: return TYPE(&stunsignedshort);
case 8: return TYPE(&stsignedint);
case 9: return TYPE(&stunsignedint);
case 10: return TYPE(&stsignedlong);
case 11: return TYPE(&stunsignedlong);
case 12: return TYPE(&stfloat);
case 13: return TYPE(&stdouble);
case 14: return TYPE(&stlongdouble);
case 15:
if (copts.longlong)
return TYPE(&stsignedlonglong);
else
return NULL;
case 16:
if (copts.longlong)
return TYPE(&stunsignedlonglong);
else
return NULL;
}
return NULL;
}
static Type *CExpr_NextPromotedArithmeticType(int *p) {
switch (++(*p)) {
case 1: return TYPE(&stsignedint);
case 2: return TYPE(&stunsignedint);
case 3: return TYPE(&stsignedlong);
case 4: return TYPE(&stunsignedlong);
case 5: return TYPE(&stdouble);
case 6: return TYPE(&stlongdouble);
case 7:
if (copts.longlong)
return TYPE(&stsignedlonglong);
else
return NULL;
case 8:
if (copts.longlong)
return TYPE(&stunsignedlonglong);
else
return NULL;
}
return NULL;
}
static Match *CExpr_MatchBuiltin(Match *matches, ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual) {
Match *scan;
Match mymatch;
if (CExpr_ImplicitConversionMatch(left, leftType, leftQual, &mymatch.conv[0])) {
if (!right || CExpr_ImplicitConversionMatch(right, rightType, rightQual, &mymatch.conv[1])) {
if (right) {
for (scan = matches; scan; scan = scan->next) {
if (
!scan->object &&
is_typesame(scan->type, leftType) &&
scan->qual == leftQual &&
is_typesame(scan->type2, rightType) &&
scan->qual2 == rightQual
)
return matches;
}
}
mymatch.next = matches;
mymatch.object = NULL;
mymatch.specialfunc = NULL;
mymatch.type = leftType;
mymatch.qual = leftQual;
mymatch.type2 = rightType;
mymatch.qual2 = rightQual;
matches = lalloc(sizeof(Match));
*matches = mymatch;
}
}
return matches;
}
static Match *CExpr_CheckIncDecBuiltin(Match *matches, short token, ENode *expr1, ENode *expr2) {
Object *object;
Type *type;
TypeFunc *tfunc;
ConversionIterator convIter;
if (IS_TYPE_CLASS(expr1->rtype)) {
CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr1->rtype));
while ((object = CExpr_ConversionIteratorNext(&convIter))) {
tfunc = TYPE_FUNC(object->type);
if (IS_TYPE_REFERENCE(tfunc->functype)) {
type = TPTR_TARGET(tfunc->functype);
switch (type->type) {
case TYPEINT:
if (type == TYPE(&stbool) && token == TK_DECREMENT)
break;
case TYPEFLOAT:
case TYPEPOINTER:
if (!CParser_IsConst(type, tfunc->qual)) {
matches = CExpr_MatchBuiltin(
matches,
expr1, type, tfunc->qual,
expr2, expr2 ? TYPE(&stsignedint) : NULL, 0
);
}
break;
}
}
}
}
return matches;
}
static Match *CExpr_CheckUnaryBuiltin(Match *matches, short token, ENode *expr) {
ConversionTypeList *typelist;
Type *type;
int typenum;
switch (token) {
case TK_INCREMENT:
case TK_DECREMENT:
return CExpr_CheckIncDecBuiltin(matches, token, expr, NULL);
case '!':
matches = CExpr_MatchBuiltin(matches, expr, TYPE(&stbool), 0, NULL, NULL, 0);
break;
case '~':
typenum = 0;
while ((type = CExpr_NextPromotedIntegralType(&typenum))) {
matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0);
}
break;
case '*':
case '+':
for (typelist = CExpr_BuildConversionTypeList(expr); typelist; typelist = typelist->next) {
if (IS_TYPE_POINTER_ONLY(typelist->type))
matches = CExpr_MatchBuiltin(matches, expr, typelist->type, typelist->qual, NULL, NULL, 0);
}
if (token != '+')
break;
case '-':
typenum = 0;
while ((type = CExpr_NextPromotedArithmeticType(&typenum))) {
matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0);
}
break;
}
return matches;
}
static Match *CExpr_CheckBinaryBuiltin(Match *matches, ENode *left, short token, ENode *right) {
int typenum1;
int typenum2;
Type *type1;
Type *type2;
Type *ptrdiff;
Boolean allowPtrDiffOnRight;
Boolean allowPtrCV;
Boolean allowPtrDiffOnLeft;
Boolean allowMemberPtrs;
Boolean allowEnum;
ConversionTypeList *leftList;
ConversionTypeList *rightList;
ConversionTypeList *scan;
switch (token) {
case TK_INCREMENT:
case TK_DECREMENT:
return CExpr_CheckIncDecBuiltin(matches, token, left, right);
case '*':
case '+':
case '-':
case '/':
case ':':
case '<':
case '>':
case TK_LOGICAL_EQ:
case TK_LOGICAL_NE:
case TK_LESS_EQUAL:
case TK_GREATER_EQUAL:
typenum1 = 0;
while ((type1 = CExpr_NextPromotedArithmeticType(&typenum1))) {
typenum2 = 0;
while ((type2 = CExpr_NextPromotedArithmeticType(&typenum2))) {
matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0);
}
}
break;
case '%':
case '&':
case '^':
case '|':
case TK_SHL:
case TK_SHR:
typenum1 = 0;
while ((type1 = CExpr_NextPromotedIntegralType(&typenum1))) {
typenum2 = 0;
while ((type2 = CExpr_NextPromotedIntegralType(&typenum2))) {
matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0);
}
}
return matches;
case TK_LOGICAL_OR:
case TK_LOGICAL_AND:
return CExpr_MatchBuiltin(matches, left, TYPE(&stbool), 0, right, TYPE(&stbool), 0);
}
allowEnum = 0;
allowMemberPtrs = 0;
allowPtrCV = 0;
allowPtrDiffOnLeft = 0;
allowPtrDiffOnRight = 0;
switch (token) {
case '+':
case '[':
allowPtrDiffOnLeft = 1;
allowPtrDiffOnRight = 1;
break;
case '-':
allowPtrCV = 1;
allowPtrDiffOnRight = 1;
break;
case ':':
case TK_LOGICAL_EQ:
case TK_LOGICAL_NE:
allowMemberPtrs = 1;
case '<':
case '>':
case TK_LESS_EQUAL:
case TK_GREATER_EQUAL:
allowPtrCV = 1;
allowEnum = 1;
break;
default:
return matches;
}
leftList = CExpr_BuildConversionTypeList(left);
rightList = CExpr_BuildConversionTypeList(right);
ptrdiff = CABI_GetPtrDiffTType();
for (scan = leftList; ; scan = scan->next) {
if (!scan) {
scan = rightList;
if (!rightList)
break;
rightList = NULL;
}
type1 = scan->type;
if (IS_TYPE_REFERENCE(type1))
type1 = TPTR_TARGET(type1);
switch (type1->type) {
case TYPEENUM:
if (allowEnum)
matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual);
break;
case TYPEPOINTER:
if (allowPtrDiffOnRight)
matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, ptrdiff, 0);
if (allowPtrDiffOnLeft)
matches = CExpr_MatchBuiltin(matches, left, ptrdiff, 0, right, type1, scan->qual);
if (allowPtrCV) {
if (IS_TYPE_POINTER_ONLY(TPTR_TARGET(type1))) {
type2 = galloc(sizeof(TypePointer));
*TYPE_POINTER(type2) = *TYPE_POINTER(type1);
TPTR_QUAL(type2) |= Q_CONST | Q_VOLATILE;
matches = CExpr_MatchBuiltin(matches, left, type2, scan->qual, right, type2, scan->qual);
} else {
matches = CExpr_MatchBuiltin(matches, left, type1, Q_CONST | Q_VOLATILE, right, type1, Q_CONST | Q_VOLATILE);
}
}
break;
case TYPEMEMBERPOINTER:
if (allowMemberPtrs)
matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual);
break;
}
}
return matches;
}
static Boolean CExpr_MatchOperands(ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual, ImplicitConv *twoResults, Boolean flag) {
if (flag) {
if (!CExpr_StandardConversionMatch(left, leftType, leftQual, 1, &twoResults[0].u.ic3.standardConv))
return 0;
twoResults[0].type = ICT_3;
} else {
if (!CExpr_ImplicitConversionMatch(left, leftType, leftQual, &twoResults[0]))
return 0;
}
if (right) {
if (!CExpr_ImplicitConversionMatch(right, rightType, rightQual, &twoResults[1]))
return 0;
}
return 1;
}
Boolean CExpr_CondOperatorMatch(ENode *left, ENode *right, Conversion *conv) {
Match *match;
if ((match = CExpr_CheckBinaryBuiltin(NULL, left, ':', right))) {
match = CExpr_FindBestMatch(match, 1, GetHashNameNode("operator?:"), NULL, NULL);
CError_ASSERT(2931, !match->object);
conv->x0 = NULL;
conv->left = CExpr_Convert(left, match->type, match->qual, 0, 1);
conv->right = CExpr_Convert(right, match->type2, match->qual2, 0, 1);
return 1;
}
return 0;
}
Boolean CExpr_OperatorMatch(short token, ENode *left, ENode *right, Conversion *conv) {
HashNameNode *name;
ENodeList *argExprs;
BClassList *path;
int hasArg;
Match *matches;
Object *object;
Object *specialfunc;
NameSpaceObjectList *list;
Type *leftType;
UInt32 leftQual;
Type *rightType;
UInt32 rightQual;
CScopeParseResult pr;
NameSpaceObjectList myList;
Match myMatch;
if (!IS_TYPE_CLASS(left->rtype)) {
if (!IS_TYPE_ENUM(left->rtype)) {
if (!right || !(IS_TYPE_CLASS(right->rtype) || IS_TYPE_ENUM(right->rtype)))
return 0;
}
} else {
CDecl_CompleteType(left->rtype);
}
name = CMangler_OperatorName(token);
path = NULL;
argExprs = lalloc(sizeof(ENodeList));
argExprs->node = left;
if (right) {
argExprs->next = lalloc(sizeof(ENodeList));
argExprs->next->node = right;
argExprs->next->next = NULL;
hasArg = 1;
} else {
argExprs->next = NULL;
hasArg = 0;
}
matches = NULL;
if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr, name)) {
if (token != '=' || (pr.bcl_18->type == left->rtype && !pr.bcl_18->next)) {
if (pr.obj_10) {
myList.next = NULL;
myList.object = pr.obj_10;
pr.nsol_14 = &myList;
} else {
CError_ASSERT(3009, pr.nsol_14);
}
for (list = pr.nsol_14; list; list = list->next) {
object = OBJECT(list->object);
if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000) {
specialfunc = object;
object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs->next);
if (!object)
continue;
} else {
specialfunc = NULL;
}
leftType = CExpr_GetImplictObjectParamType(object, &leftQual);
if (right) {
if (!CExpr_HasNParams(object, 1))
continue;
rightType = CExpr_GetParamType(object, 0, &rightQual);
} else {
if (!CExpr_HasNParams(object, 0))
continue;
}
if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 1)) {
myMatch.object = object;
myMatch.specialfunc = specialfunc;
myMatch.next = matches;
matches = lalloc(sizeof(Match));
*matches = myMatch;
path = pr.bcl_18;
}
}
}
}
}
if (CScope_FindNonClassObject(cscope_current, &pr, name)) {
if (pr.obj_10) {
myList.next = NULL;
myList.object = pr.obj_10;
pr.nsol_14 = &myList;
}
} else {
pr.nsol_14 = NULL;
}
if (copts.arg_dep_lookup)
pr.nsol_14 = CScope_ArgumentDependentNameLookup(pr.nsol_14, name, argExprs, 1);
for (list = pr.nsol_14; list; list = list->next) {
object = OBJECT(list->object);
if (object->otype == OT_OBJECT && IS_TYPE_NONMETHOD(object->type)) {
if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000) {
specialfunc = object;
object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs);
if (!object)
continue;
} else {
specialfunc = NULL;
}
leftType = CExpr_GetParamType(object, 0, &leftQual);
if (right) {
if (!CExpr_HasNParams(object, 2))
continue;
rightType = CExpr_GetParamType(object, 1, &rightQual);
} else {
if (!CExpr_HasNParams(object, 1))
continue;
}
if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 0)) {
myMatch.object = object;
myMatch.specialfunc = specialfunc;
myMatch.next = matches;
matches = lalloc(sizeof(Match));
*matches = myMatch;
}
}
}
if (right)
matches = CExpr_CheckBinaryBuiltin(matches, left, token, right);
else
matches = CExpr_CheckUnaryBuiltin(matches, token, left);
if (matches) {
conv->x0 = NULL;
conv->left = NULL;
conv->right = NULL;
matches = CExpr_FindBestMatch(matches, hasArg, name, NULL, argExprs);
object = matches->object;
if (!object) {
if (IS_TYPE_CLASS(left->rtype))
conv->left = CExpr_Convert(left, matches->type, matches->qual, 0, 1);
else
conv->left = left;
if (right) {
if (IS_TYPE_CLASS(right->rtype))
conv->right = CExpr_Convert(right, matches->type2, matches->qual2, 0, 1);
else
conv->right = right;
}
return 1;
}
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type))) {
CError_ASSERT(3125, path);
left = CExpr_GenericFuncCall(path, argExprs->node, 0, object, NULL, NULL, argExprs->next, 0, 0, 1);
} else {
left = CExpr_GenericFuncCall(NULL, NULL, 0, object, NULL, NULL, argExprs, 0, 0, 1);
}
conv->x0 = checkreference(left);
return 1;
}
return 0;
}
static ENode *CExpr_ClassCopyInit(TypeClass *tclass, ENode *expr1, ENode *expr2) {
Object *best;
NameSpaceObjectList *list;
ObjectList *objlist;
ObjectList *objlistEntry;
ENodeList *argExprs;
FuncArg *arg;
Type *type;
Object *object;
ImplicitConv bestConv;
ImplicitConv conv;
BClassList path;
ConversionIterator convIter;
best = NULL;
objlist = NULL;
for (list = CClass_Constructor(tclass); list; list = list->next) {
object = OBJECT(list->object);
if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type) && !(object->qual & Q_EXPLICIT)) {
arg = TYPE_FUNC(object->type)->args;
CError_ASSERT(3199, arg);
arg = arg->next;
if (tclass->flags & CLASS_FLAGS_20) {
CError_ASSERT(3203, arg);
arg = arg->next;
}
if (
arg &&
arg != &elipsis &&
(!arg->next || arg->next->dexpr) &&
CExpr_ImplicitConversionMatch(expr2, arg->type, arg->qual, &conv)
)
{
if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) {
best = object;
bestConv = conv;
objlist = NULL;
} else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) {
objlistEntry = lalloc(sizeof(ObjectList));
objlistEntry->next = objlist;
objlistEntry->object = object;
objlist = objlistEntry;
}
}
}
}
if (IS_TYPE_CLASS(expr2->rtype)) {
CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr2->rtype));
while ((object = CExpr_ConversionIteratorNext(&convIter))) {
type = TYPE_FUNC(object->type)->functype;
if (IS_TYPE_REFERENCE(type))
type = TPTR_TARGET(type);
if (
IS_TYPE_CLASS(type) &&
(tclass == TYPE_CLASS(type) || CClass_IsBaseClass(tclass, TYPE_CLASS(type), NULL, 0, 0))
)
{
CError_ASSERT(3248, TYPE_FUNC(object->type)->args &&
IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->args->type));
type = galloc(sizeof(TypePointer));
*TYPE_POINTER(type) = *TYPE_POINTER(TYPE_FUNC(object->type)->args->type);
TPTR_QUAL(type) = Q_REFERENCE;
if (CExpr_ImplicitConversionMatch(expr2, type, TYPE_FUNC(object->type)->args->qual, &conv)) {
if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) {
best = object;
bestConv = conv;
objlist = NULL;
} else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) {
objlistEntry = lalloc(sizeof(ObjectList));
objlistEntry->next = objlist;
objlistEntry->object = object;
objlist = objlistEntry;
}
}
}
}
}
if (objlist)
CError_OverloadedFunctionError(best, objlist);
if (!best) {
CError_Error(CErrorStr209, expr2->rtype, ENODE_QUALS(expr2), tclass, 0);
return expr1;
}
CError_ASSERT(3284, IS_TYPE_POINTER_ONLY(expr1->rtype));
expr1 = makemonadicnode(expr1, EINDIRECT);
expr1->rtype = TYPE(tclass);
argExprs = lalloc(sizeof(ENodeList));
argExprs->node = expr2;
if (tclass->flags & CLASS_FLAGS_20) {
argExprs->next = lalloc(sizeof(ENodeList));
argExprs->next->next = NULL;
argExprs->next->node = intconstnode(TYPE(&stsignedshort), 1);
} else {
argExprs->next = NULL;
}
path.next = NULL;
path.type = TYPE(tclass);
expr1 = CExpr_GenericFuncCall(&path, expr1, 0, best, NULL, NULL, argExprs, 0, 0, 1);
if (ENODE_IS2(expr1, EFUNCCALL, EFUNCCALLP))
expr1->rtype = CDecl_NewPointerType(TYPE(tclass));
expr1 = makemonadicnode(expr1, EINDIRECT);
expr1->rtype = TYPE(tclass);
return expr1;
}