summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/C/CExprConvMatch.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/C/CExprConvMatch.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-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.c2518
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;
+}