diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/C/CExprConvMatch.c | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-main.tar.gz MWCC-main.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CExprConvMatch.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CExprConvMatch.c | 2518 |
1 files changed, 2518 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CExprConvMatch.c b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c new file mode 100644 index 0000000..5cc145f --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c @@ -0,0 +1,2518 @@ +#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_METHOD); + CError_ASSERT(100, !TYPE_METHOD(object->type)->is_static); + 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; +} + +CW_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; + +CW_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_USED; + 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_INLINE_DATA) && + 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_IS_TEMPL) { + 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_IS_TEMPL) { + 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_HAS_VBASES) && !(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_USED; + + 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_HAS_VBASES) { + 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_METHOD)) { + convs->type = ICT_0; + } else if (TYPE_METHOD(func->type)->is_static) { + convs->type = ICT_0; + } else if (TYPE_FUNC(func->type)->flags & FUNC_IS_CTOR) { + 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_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)->is_static) + argsA = argsA->next; + argsB = TYPE_FUNC(object2->type)->args; + if (argsB && !TYPE_METHOD(object2->type)->is_static) + argsB = argsB->next; + if (is_arglistsame(argsA, argsB)) + break; + } + } + + if (j) + continue; + } + + if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) { + 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; + NameResult 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_IS_TEMPL) { + 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_IS_TEMPL) { + 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_HAS_VBASES) { + 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_HAS_VBASES) { + 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; +} |