#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; }