mirror of https://git.wuffs.org/MWCC
2519 lines
81 KiB
C
2519 lines
81 KiB
C
#include "compiler/CExpr.h"
|
|
#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;
|
|
}
|