#include "compiler/CTemplateFunc.h" #include "compiler/CABI.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CExpr.h" #include "compiler/CInline.h" #include "compiler/CInt64.h" #include "compiler/CParser.h" #include "compiler/CTemplateTools.h" #include "compiler/CompilerTools.h" #include "compiler/objects.h" #include "compiler/scopes.h" #include "compiler/templates.h" #include "compiler/types.h" static Boolean ctempl_conversion_deduction; static UInt8 ctempl_explicitargs_nindex; static int ctempl_explicitargs_num; static Boolean ctempl_explicitargs_all; // forward decls static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag); static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag); static void CTemplFunc_SetupTypeDeduce(TypeDeduce *deduce, TemplateFunction *templ, TemplArg *args) { memclrw(deduce, sizeof(TypeDeduce)); if (templ->tfunc->nspace->theclass && (templ->tfunc->nspace->theclass->flags & CLASS_FLAGS_100)) deduce->tmclass = TEMPL_CLASS(templ->tfunc->nspace->theclass); deduce->params = templ->params; deduce->args = args; } Boolean CTempl_CanDeduceFunc(Object *object, TypeFunc *tfunc, TemplArg *args) { DeduceInfo info; int i; if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object)->params, args, 0)) { if (CTempl_DeduceType(object->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) { for (i = 0; i < info.maxCount; i++) { if (!info.args[i].is_deduced) return 0; } return 1; } } return 0; } static TemplFuncInstance *CTempl_GetCreateFuncInstance(Object *funcobj, TemplArg *args, Object *object2) { TemplFuncInstance *inst; TemplateFunction *templ; Object *instobj; TemplParam *param; TemplArg *arg; TemplArg *last; short paramCount; short i; TypeDeduce deduce; templ = CTemplTool_GetFuncTempl(funcobj); paramCount = 0; param = templ->params; while (param) { param = param->next; paramCount++; } for (i = 1, arg = args; i < paramCount; i++, arg++) arg->next = arg + 1; arg->next = NULL; for (inst = templ->instances; inst; inst = inst->next) { if (CTemplTool_EqualArgs(inst->args, args)) { if (object2) inst->object = object2; return inst; } } inst = galloc(sizeof(TemplFuncInstance)); memclrw(inst, sizeof(TemplFuncInstance)); for (i = 0, arg = NULL; i < paramCount; i++) { if (arg) { last->next = galloc(sizeof(TemplArg)); last = last->next; } else { last = galloc(sizeof(TemplArg)); arg = last; } *last = *args; last->next = NULL; args++; if (last->pid.type == TPT_NONTYPE) { CError_ASSERT(114, last->data.paramdecl.expr); last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1); } } inst->args = arg; inst->next = templ->instances; templ->instances = inst; if (!object2) { instobj = CParser_NewFunctionObject(NULL); instobj->access = funcobj->access; instobj->nspace = funcobj->nspace; instobj->sclass = funcobj->sclass; instobj->qual = funcobj->qual | Q_80000; instobj->name = templ->name; instobj->u.func.inst = inst; CTemplFunc_SetupTypeDeduce(&deduce, templ, inst->args); if (funcobj->nspace->theclass && (funcobj->nspace->theclass->flags & CLASS_FLAGS_800)) { deduce.tmclass = TEMPL_CLASS_INST(funcobj->nspace->theclass)->templ; deduce.inst = TEMPL_CLASS_INST(funcobj->nspace->theclass); } instobj->type = CTemplTool_DeduceTypeCopy(&deduce, funcobj->type, &instobj->qual); inst->object = instobj; if (IS_TYPE_FUNC(instobj->type)) { TYPE_FUNC(instobj->type)->flags &= ~FUNC_FLAGS_2; if (TYPE_FUNC(instobj->type)->flags & FUNC_FLAGS_1000) { FuncArg *funcarg; CError_ASSERT(152, TYPE_FUNC(instobj->type)->flags & FUNC_FLAGS_METHOD); CError_ASSERT(153, funcarg = TYPE_FUNC(instobj->type)->args); if (TYPE_METHOD(instobj->type)->theclass->flags & CLASS_FLAGS_20) CError_ASSERT(156, funcarg = funcarg->next); if (funcarg->next) CDecl_CheckCtorIntegrity(funcarg->next, TYPE_METHOD(instobj->type)->theclass); } } if ((instobj->qual & Q_INLINE) && templ->stream.tokens) CInline_AddTemplateFunctionAction(instobj, templ, inst); } else { inst->object = object2; } return inst; } TemplFuncInstance *CTempl_CheckFuncInstance(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2) { DeduceInfo info; int i; if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object1)->params, args, 1)) return NULL; if (!CTempl_DeduceType(object1->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) return NULL; i = 0; while (i < info.maxCount) { if (!info.args[i++].is_deduced) return NULL; } return CTempl_GetCreateFuncInstance(object1, info.args, object2); } TemplFuncInstance *CTempl_DeduceFunc(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2, Boolean flag) { return CTempl_CheckFuncInstance(object1, tfunc, args, object2); } static Boolean CTempl_FuncIsAtLeastAsSpecialized(Object *func1, Object *func2) { int i; FuncArg *arg1; FuncArg *arg2; Type *type1; Type *type2; UInt32 qual1; UInt32 qual2; DeduceInfo info; arg1 = TYPE_FUNC(func2->type)->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type))) arg1 = arg1->next; i = 0; while (1) { if (!arg1) break; CError_ASSERT(231, arg1->type != &stvoid); if (arg1 == &elipsis) break; if (arg1 == &oldstyle) break; arg1 = arg1->next; i++; } if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(func2)->params, NULL, 0)) return 0; arg1 = TYPE_FUNC(func1->type)->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func1->type))) arg1 = arg1->next; arg2 = TYPE_FUNC(func2->type)->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type))) arg2 = arg2->next; while (i > 0) { if (!arg1) break; if (arg1 == &elipsis) break; if (arg1 == &oldstyle) break; CError_ASSERT(255, arg2); type1 = arg1->type; qual1 = arg1->qual & (Q_CONST | Q_VOLATILE); qual2 = arg2->qual & (Q_CONST | Q_VOLATILE); type2 = arg2->type; if (!CTemplTool_IsTemplateArgumentDependentType(type2)) { if (IS_TYPE_REFERENCE(type1)) type1 = TPTR_TARGET(type1); type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); if (IS_TYPE_REFERENCE(type2)) type2 = TPTR_TARGET(type2); type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); if (!is_typesame(type1, type2) || qual1 != qual2) return 0; } else { if (!CTempl_DeduceType(type2, qual2, type1, qual1, info.args, 0, 0)) return 0; } arg1 = arg1->next; arg2 = arg2->next; i--; } return 1; } Boolean CTempl_FuncIsMoreSpecialized(Object *object1, Object *object2) { return CTempl_FuncIsAtLeastAsSpecialized(object1, object2) && !CTempl_FuncIsAtLeastAsSpecialized(object2, object1); } Object *CTempl_PartialOrdering(Object *object, ObjectList *list, int count) { int i; int j; Object **array; ObjectList *scan; Object *arrayBuffer[16]; for (count = 1, scan = list; scan; scan = scan->next) { if (IS_TEMPL_FUNC(scan->object->type)) count++; } if (count > 16) array = lalloc(sizeof(Object *) * count); else array = arrayBuffer; array[0] = object; for (i = 1, scan = list; scan; scan = scan->next) { if (IS_TEMPL_FUNC(scan->object->type)) array[i++] = scan->object; } for (i = 0; i < count; i++) { if (array[i]) { for (j = 0; j < count; j++) { if (array[j] && i != j && CTempl_FuncIsMoreSpecialized(array[i], array[j])) array[j] = NULL; } } } object = NULL; for (i = 0; i < count; i++) { if (array[i]) { if (object) return NULL; object = array[i]; } } return object; } int CTempl_GetTemplateArgumentExpressionIndex(TemplArg *arg) { CError_ASSERT(529, arg->data.paramdecl.expr); if (ENODE_IS(arg->data.paramdecl.expr, ETEMPLDEP) && arg->data.paramdecl.expr->data.templdep.subtype == TDE_PARAM) return arg->data.paramdecl.expr->data.templdep.u.pid.index; return -1; } static Type *CTempl_GetSpecifiedType(TemplateFunction *templ, Type *type, UInt32 qual, TemplArg *args, UInt32 *resultQual) { TypeDeduce deduce; CTemplFunc_SetupTypeDeduce(&deduce, templ, args); *resultQual = qual; return CTemplTool_DeduceTypeCopy(&deduce, type, resultQual); } static Boolean CTempl_DeduceTemplateArgs(TemplArg *args1, TemplArg *args2, TemplArg *argArray) { int index; while (1) { if (!args1) return !args2; if (!args2) return 0; if (args1->pid.type != args2->pid.type) return 0; switch (args1->pid.type) { case TPT_TYPE: if (!CTempl_DeduceType1( args1->data.typeparam.type, args1->data.typeparam.qual, args2->data.typeparam.type, args2->data.typeparam.qual, argArray, 1 )) return 0; break; case TPT_NONTYPE: if (CTemplTool_IsTemplateArgumentDependentExpression(args1->data.paramdecl.expr)) { index = CTempl_GetTemplateArgumentExpressionIndex(args1); if (index < 0) return 1; if (argArray[index].is_deduced) { if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, argArray[index].data.paramdecl.expr)) return 0; } else { argArray[index].data.paramdecl.expr = args2->data.paramdecl.expr; argArray[index].pid.type = TPT_NONTYPE; argArray[index].is_deduced = 1; } } else { if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, args1->data.paramdecl.expr)) return 0; } break; case TPT_TEMPLATE: if (!IS_TEMPL_CLASS(args2->data.ttargtype)) return 0; index = args1->pid.index; if (argArray[index].is_deduced) { if (args2->data.ttargtype != argArray[index].data.ttargtype) return 0; } else { argArray[index].data.ttargtype = args2->data.ttargtype; argArray[index].pid.type = TPT_TEMPLATE; argArray[index].is_deduced = 1; } break; default: CError_FATAL(640); } args1 = args1->next; args2 = args2->next; } } static Boolean CTempl_DeduceTemplDepTemplate(TemplClass *templ1, TemplArg *args1, TemplClass *templ2, TemplArg *args2, TemplArg *argArray) { if (templ1 != templ2) return 0; return CTempl_DeduceTemplateArgs(args2, args1, argArray); } static Boolean CTempl_DeduceTemplateType(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray) { TemplClassInst *scan; for (scan = templ->instances; scan; scan = scan->next) { if (scan == inst) return CTempl_DeduceTemplateArgs(args, scan->oargs ? scan->oargs : scan->inst_args, argArray); } return 0; } static Boolean CTempl_DeduceTemplateTypeBase(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray, Boolean flag) { ClassList *base; if (CTempl_DeduceTemplateType(templ, args, inst, argArray)) return 1; if (flag) { for (base = inst->theclass.bases; base; base = base->next) { if (CTempl_DeduceTemplateType(templ, args, TEMPL_CLASS_INST(base->base), argArray)) { ctempl_conversion_deduction = 1; return 1; } } for (base = inst->theclass.bases; base; base = base->next) { if (CTempl_DeduceTemplateTypeBase(templ, args, TEMPL_CLASS_INST(base->base), argArray, 1)) { ctempl_conversion_deduction = 1; return 1; } } } return 0; } static Boolean CTempl_DeduceQualTemplate(TypeTemplDep *type1, TemplArg *args1, Type *type2, TemplArg *argArray) { int index; if (type1->dtype == TEMPLDEP_ARGUMENT && type1->u.pid.type == TPT_TEMPLATE) { index = type1->u.pid.index; if (IS_TEMPL_CLASS_INST(type2)) { if (argArray[index].is_deduced) { if (argArray[index].data.ttargtype != TYPE(TEMPL_CLASS_INST(type2)->templ)) return 0; } else { argArray[index].data.ttargtype = TYPE(TEMPL_CLASS_INST(type2)->templ); argArray[index].pid.type = TPT_TEMPLATE; argArray[index].is_deduced = 1; } return CTempl_DeduceTemplateArgs(args1, TEMPL_CLASS_INST(type2)->inst_args, argArray); } if (IS_TYPE_TEMPLATE(type2)) { if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) { if (argArray[index].is_deduced) { if (argArray[index].data.ttargtype != TYPE(TYPE_TEMPLATE(type2)->u.templ.templ)) return 0; } else { argArray[index].data.ttargtype = TYPE(TYPE_TEMPLATE(type2)->u.templ.templ); argArray[index].pid.type = TPT_TEMPLATE; argArray[index].is_deduced = 1; } return CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.templ.args, argArray); } if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_QUALTEMPL) { return CTempl_DeduceTypeTemplDep(type1, 0, TYPE(TYPE_TEMPLATE(type2)->u.qualtempl.type), 0, argArray, 1) && CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.qualtempl.args, argArray); } } } return 0; } static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) { Type *tmptype; UInt32 tmpqual; short index; Boolean f; UInt32 modqual; switch (type1->dtype) { case TEMPLDEP_ARGUMENT: index = type1->u.pid.index; tmptype = type2; if (type1->u.pid.type == TPT_TEMPLATE) { if (argArray[index].is_deduced) { if (!is_typesame(tmptype, argArray[index].data.ttargtype)) return 0; } else { argArray[index].data.ttargtype = type2; argArray[index].pid.type = TPT_TEMPLATE; argArray[index].is_deduced = 1; } return 1; } switch (type2->type) { case TYPEPOINTER: tmpqual = qual2; f = 0; qual2 = TPTR_QUAL(type2); modqual = qual2; if ((modqual & Q_CONST) && (qual1 & Q_CONST)) { modqual &= ~Q_CONST; f = 1; } if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) { modqual &= ~Q_VOLATILE; f = 1; } if (f) { tmptype = galloc(sizeof(TypePointer)); *TYPE_POINTER(tmptype) = *TYPE_POINTER(type2); TPTR_QUAL(tmptype) = modqual; } if (flag && (qual2 | modqual) != (qual1 | modqual)) return 0; break; case TYPEMEMBERPOINTER: tmpqual = qual2; f = 0; qual2 = TYPE_MEMBER_POINTER(type2)->qual; modqual = qual2; if ((modqual & Q_CONST) && (qual1 & Q_CONST)) { modqual &= ~Q_CONST; f = 1; } if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) { modqual &= ~Q_VOLATILE; f = 1; } if (f) { tmptype = galloc(sizeof(TypeMemberPointer)); *TYPE_MEMBER_POINTER(tmptype) = *TYPE_MEMBER_POINTER(type2); TYPE_MEMBER_POINTER(tmptype)->qual = modqual; } if (flag && (qual2 | modqual) != (qual1 | modqual)) return 0; break; default: tmpqual = 0; if ((qual2 & Q_CONST) && !(qual1 & Q_CONST)) tmpqual |= Q_CONST; if ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE)) tmpqual |= Q_VOLATILE; if (flag && (qual2 | tmpqual) != (qual1 | tmpqual)) return 0; } if (argArray[index].is_deduced) { if (!is_typesame(tmptype, argArray[index].data.typeparam.type) || tmpqual != argArray[index].data.typeparam.qual) return 0; } else { argArray[index].data.typeparam.type = tmptype; argArray[index].data.typeparam.qual = tmpqual; argArray[index].pid.type = TPT_TYPE; argArray[index].is_deduced = 1; } return 1; case TEMPLDEP_QUALNAME: return 1; case TEMPLDEP_TEMPLATE: if (IS_TYPE_CLASS(type2)) return CTempl_DeduceTemplateTypeBase( type1->u.templ.templ, type1->u.templ.args, TEMPL_CLASS_INST(type2), argArray, 0); if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) return CTempl_DeduceTemplDepTemplate( TYPE_TEMPLATE(type2)->u.templ.templ, TYPE_TEMPLATE(type2)->u.templ.args, type1->u.templ.templ, type1->u.templ.args, argArray ); return 0; case TEMPLDEP_ARRAY: if (IS_TYPE_ARRAY(type2)) { SInt32 elements; if (!CTempl_DeduceType1(type1->u.array.type, qual1, TPTR_TARGET(type2), qual2, argArray, flag)) return 0; if (ENODE_IS(type1->u.array.index, EINTCONST)) { CError_ASSERT(961, TPTR_TARGET(type2)->size); return (type2->size / TPTR_TARGET(type2)->size) == CInt64_GetULong(&type1->u.array.index->data.intval); } if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM) return 1; CError_ASSERT(970, TPTR_TARGET(type2)->size); elements = type2->size / TPTR_TARGET(type2)->size; index = type1->u.array.index->data.templdep.u.pid.index; if (argArray[index].is_deduced) { CError_ASSERT(976, ENODE_IS(argArray[index].data.paramdecl.expr, EINTCONST)); return elements == CInt64_GetULong(&argArray[index].data.paramdecl.expr->data.intval); } else { argArray[index].data.paramdecl.expr = intconstnode(CABI_GetPtrDiffTType(), elements); argArray[index].pid.type = TPT_NONTYPE; argArray[index].is_deduced = 1; return 1; } } else if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_ARRAY) { if (!CTempl_DeduceType1(type1->u.array.type, qual1, TYPE_TEMPLATE(type2)->u.array.type, qual2, argArray, flag)) return 0; if (ENODE_IS(type1->u.array.index, EINTCONST)) { return ENODE_IS(TYPE_TEMPLATE(type2)->u.array.index, EINTCONST) && CInt64_Equal(type1->u.array.index->data.intval, TYPE_TEMPLATE(type2)->u.array.index->data.intval); } if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM) return 1; index = type1->u.array.index->data.templdep.u.pid.index; if (argArray[index].is_deduced) { return CTemplTool_EqualExprTypes(TYPE_TEMPLATE(type2)->u.array.index, argArray[index].data.paramdecl.expr); } else { argArray[index].data.paramdecl.expr = TYPE_TEMPLATE(type2)->u.array.index; argArray[index].pid.type = TPT_NONTYPE; argArray[index].is_deduced = 1; return 1; } } return 0; case TEMPLDEP_QUALTEMPL: return CTempl_DeduceQualTemplate(type1->u.qualtempl.type, type1->u.qualtempl.args, type2, argArray); case TEMPLDEP_BITFIELD: default: CError_FATAL(1022); return 1; } } static Boolean CTempl_DeduceFuncType(TypeFunc *tfunc1, TypeFunc *tfunc2, TemplArg *argArray) { FuncArg *arg1; FuncArg *arg2; Type *type2; Type *type1; UInt32 qual2; UInt32 qual1; arg1 = tfunc1->args; arg2 = tfunc2->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc1) && !IS_TYPEFUNC_METHOD(tfunc2)) { CError_ASSERT(1045, arg1); arg1 = arg1->next; } while (1) { if (arg1 == NULL) return !arg2; if (arg1 == &oldstyle) return arg2 == &oldstyle; if (arg1 == &elipsis) return arg2 == &elipsis; if (arg2 == NULL || arg2 == &oldstyle || arg2 == &elipsis) return 0; qual2 = arg2->qual; type2 = CParser_RemoveTopMostQualifiers(arg2->type, &qual2); qual1 = arg1->qual; type1 = CParser_RemoveTopMostQualifiers(arg1->type, &qual1); if (!CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, 1)) return 0; arg1 = arg1->next; arg2 = arg2->next; } } static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) { while (1) { switch (type1->type) { case TYPETEMPLATE: return CTempl_DeduceTypeTemplDep(TYPE_TEMPLATE(type1), qual1, type2, qual2, argArray, flag); case TYPEVOID: case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPESTRUCT: case TYPECLASS: return type1 == type2; case TYPEMEMBERPOINTER: if (type1->type != type2->type || TYPE_MEMBER_POINTER(type1)->qual != TYPE_MEMBER_POINTER(type2)->qual) return 0; if (!CTempl_DeduceType1(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray, flag)) return 0; type1 = TYPE_MEMBER_POINTER(type1)->ty2; type2 = TYPE_MEMBER_POINTER(type2)->ty2; continue; case TYPEARRAY: if (type2->type != TYPEARRAY) return 0; type1 = TPTR_TARGET(type1); type2 = TPTR_TARGET(type2); continue; case TYPEPOINTER: if (type2->type != TYPEPOINTER || TPTR_QUAL(type1) != TPTR_QUAL(type2)) return 0; type1 = TPTR_TARGET(type1); type2 = TPTR_TARGET(type2); continue; case TYPEFUNC: if (type1->type != type2->type) return 0; if (CTempl_DeduceType1(TYPE_FUNC(type1)->functype, TYPE_FUNC(type1)->qual, TYPE_FUNC(type2)->functype, TYPE_FUNC(type2)->qual, argArray, flag)) return CTempl_DeduceFuncType(TYPE_FUNC(type1), TYPE_FUNC(type2), argArray); return 0; default: CError_FATAL(1124); } } } static Boolean CTempl_DeduceType2(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { while (1) { switch (type1->type) { case TYPEPOINTER: if (type2->type != TYPEPOINTER) return 0; if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1))) return 0; type1 = TPTR_TARGET(type1); type2 = TPTR_TARGET(type2); continue; case TYPEMEMBERPOINTER: if (type2->type != TYPEMEMBERPOINTER) return 0; if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual)) return 0; if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray)) return 0; type1 = TYPE_MEMBER_POINTER(type1)->ty2; type2 = TYPE_MEMBER_POINTER(type2)->ty2; continue; default: if (CParser_IsSameOrMoreCVQualified(qual2, qual1)) return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0); return 0; } } } static Boolean CTempl_DeduceType3(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { Boolean flag = 0; while (1) { switch (type1->type) { case TYPEPOINTER: flag = 1; if (type2->type != TYPEPOINTER) return 0; if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1))) return 0; type1 = TPTR_TARGET(type1); type2 = TPTR_TARGET(type2); continue; case TYPEMEMBERPOINTER: flag = 1; if (type2->type != TYPEMEMBERPOINTER) return 0; if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual)) return 0; if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray)) return 0; type1 = TYPE_MEMBER_POINTER(type1)->ty2; type2 = TYPE_MEMBER_POINTER(type2)->ty2; continue; default: if (!flag) return 0; if (CParser_IsSameOrMoreCVQualified(qual2, qual1)) return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0); return 0; } } } static Boolean CTempl_DeduceType4(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { if (IS_TYPE_POINTER_ONLY(type1)) { if (!IS_TYPE_POINTER_ONLY(type2)) return 0; if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type1), TPTR_QUAL(type2))) return 0; type1 = TPTR_TARGET(type1); type2 = TPTR_TARGET(type2); } if (IS_TYPE_TEMPLATE(type1) && TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_TEMPLATE && IS_TYPE_CLASS(type2)) { if (CParser_IsSameOrMoreCVQualified(qual1, qual2)) return CTempl_DeduceTemplateTypeBase( TYPE_TEMPLATE(type1)->u.templ.templ, TYPE_TEMPLATE(type1)->u.templ.args, TEMPL_CLASS_INST(type2), argArray, 1); else return 0; } return 0; } Boolean CTempl_DeduceType(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag1, Boolean flag2) { Boolean flag31; Boolean flag8; flag31 = 0; flag8 = 1; if (flag1 || flag2) { if (IS_TYPE_REFERENCE(type1)) { type1 = TPTR_TARGET(type1); flag31 = 1; } else { switch (type2->type) { case TYPEFUNC: type2 = CDecl_NewPointerType(type2); break; case TYPEARRAY: type2 = CDecl_NewPointerType(TPTR_TARGET(type2)); break; } type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); } flag8 = 0; } if (CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, flag8)) return 1; if (flag1 || flag2) { if (flag31 && CTempl_DeduceType2(type1, qual1, type2, qual2, argArray)) return 1; if (CTempl_DeduceType3(type1, qual1, type2, qual2, argArray)) return 1; if (flag1 && CTempl_DeduceType4(type1, qual1, type2, qual2, argArray)) return 1; } return 0; } static Boolean CTempl_TypeNeedsDeduction(Type *type) { FuncArg *arg; Boolean result; while (1) { switch (type->type) { case TYPETEMPLATE: switch (TYPE_TEMPLATE(type)->dtype) { case TEMPLDEP_ARGUMENT: if ( TYPE_TEMPLATE(type)->u.pid.index >= ctempl_explicitargs_num || TYPE_TEMPLATE(type)->u.pid.nindex != ctempl_explicitargs_nindex ) ctempl_explicitargs_all = 0; return 1; case TEMPLDEP_QUALNAME: CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qual.type)); return 1; case TEMPLDEP_TEMPLATE: ctempl_explicitargs_all = 0; return 1; case TEMPLDEP_ARRAY: CTempl_TypeNeedsDeduction(TYPE_TEMPLATE(type)->u.array.type); ctempl_explicitargs_all = 0; return 1; case TEMPLDEP_QUALTEMPL: CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qualtempl.type)); ctempl_explicitargs_all = 0; return 1; case TEMPLDEP_BITFIELD: default: CError_FATAL(1357); } case TYPEVOID: case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPESTRUCT: case TYPECLASS: return 0; case TYPEMEMBERPOINTER: result = 0; if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty1)) result = 1; if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty2)) result = 1; return result; case TYPEPOINTER: case TYPEARRAY: type = TPTR_TARGET(type); continue; case TYPEFUNC: result = 0; for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis; arg = arg->next) { if (CTempl_TypeNeedsDeduction(arg->type)) result = 1; } if (CTempl_TypeNeedsDeduction(TYPE_FUNC(type)->functype)) result = 1; return result; default: CError_FATAL(1389); } } } static Boolean CTempl_MatchTemplFunc(Object *object, DeduceInfo *info, FuncArg *args, ENodeList *exprs, Match13 *match13ptr) { Match13 match13; int i; memclrw(&match13, sizeof(match13)); while (1) { if (!args || args->type == &stvoid) { if (!exprs) break; return 0; } if (args == &elipsis) break; if (args == &oldstyle) break; if (!exprs) { if (args->dexpr) break; return 0; } ctempl_explicitargs_nindex = info->x12C; ctempl_explicitargs_num = info->count; ctempl_explicitargs_all = 1; if (CTempl_TypeNeedsDeduction(args->type)) { if (!ctempl_explicitargs_all) { UInt32 cv2; UInt32 cv1; Type *type2; Type *type1; UInt32 qual2; UInt32 qual1; type1 = args->type; qual1 = args->qual & (Q_CONST | Q_VOLATILE); type2 = exprs->node->rtype; qual2 = ENODE_QUALS(exprs->node); if (IS_TYPE_REFERENCE(type1)) { type1 = TPTR_TARGET(type1); cv1 = CParser_GetCVTypeQualifiers(type1, qual1); cv2 = CParser_GetCVTypeQualifiers(type2, qual2); if ( (!(cv1 & Q_CONST) && (cv2 & Q_CONST)) || (!(cv1 & Q_VOLATILE) && (cv2 & Q_VOLATILE)) ) return 0; if (!(cv1 & Q_CONST) && !CExpr_IsLValue(exprs->node)) return 0; } type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); if (ENODE_IS(exprs->node, EOBJREF) && IS_TEMPL_FUNC(exprs->node->data.objref->type)) return 0; if (ENODE_IS(exprs->node, EOBJLIST)) { NameSpaceObjectList *list; for (list = exprs->node->data.objlist.list; list; list = list->next) { if (list->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(list->object)->type)) break; } if (list) return 0; if (IS_TYPE_FUNC(type2)) type2 = CDecl_NewPointerType(type2); } ctempl_conversion_deduction = 0; if (!CTempl_DeduceType(type1, qual1, type2, qual2, info->args, 1, 0)) return 0; if (ctempl_conversion_deduction) match13.anotherm5.x4++; else match13.anotherm5.x0++; if (IS_TYPE_POINTER_ONLY(args->type)) CExpr_MatchCV(type2, qual2, args->type, args->qual, &match13); } else { Type *type; UInt32 qual; type = CTempl_GetSpecifiedType(CTemplTool_GetFuncTempl(object), args->type, args->qual, info->args, &qual); if (type && !CExpr_MatchAssign(type, qual, exprs->node, &match13)) return 0; } } else { if (copts.old_argmatch && !CExpr_MatchAssign(args->type, args->qual, exprs->node, &match13)) return 0; } exprs = exprs->next; args = args->next; } for (i = 0; i < info->maxCount; i++) { if (!info->args[i].is_deduced) return 0; info->args[i].next = &info->args[i + 1]; } info->args[info->maxCount].next = NULL; return CExpr_MatchCompare(object, match13ptr, &match13); } void CTempl_FuncMatch(NameSpaceObjectList *list, TemplArg *args, ENodeList *argexprs, Match13 *match13ptr, ENode *expr) { Object *obj; Object *success; Object *object1; FuncMatchArgs funcMatchArgs; DeduceInfo info; DeduceInfo info2; object1 = match13ptr->obj; success = NULL; while (list) { obj = OBJECT(list->object); if ( obj->otype == OT_OBJECT && IS_TEMPL_FUNC(obj->type) && CExpr_GetFuncMatchArgs(obj, argexprs, expr, &funcMatchArgs) && CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(obj)->params, args, 0) && CTempl_MatchTemplFunc(obj, &info, funcMatchArgs.args, funcMatchArgs.exprs, match13ptr) ) { info2 = info; if (info.args == info.argBuffer) info2.args = info2.argBuffer; success = obj; } list = list->next; } if (success) { if (match13ptr->list) { ENodeList *argexpr = argexprs; int argexprcount = 0; while (argexpr) { argexpr = argexpr->next; argexprcount++; } obj = CTempl_PartialOrdering(match13ptr->obj, match13ptr->list, argexprcount); if (!obj) { CError_OverloadedFunctionError(match13ptr->obj, match13ptr->list); match13ptr->list = NULL; if (object1) match13ptr->obj = object1; else match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object; } else { NameSpaceObjectList mylist; mylist.next = NULL; mylist.object = OBJ_BASE(obj); memclrw(match13ptr, sizeof(Match13)); CTempl_FuncMatch(&mylist, args, argexprs, match13ptr, expr); } } else { match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object; } } else { match13ptr->obj = object1; } } static Boolean CExpr_DeduceFromObjList(FuncArg *arg, NameSpaceObjectList *list, DeduceInfo *info) { TemplArg *savebuf; NameSpaceObjectList *scan; SInt32 size; for (scan = list; scan; scan = scan->next) { if (scan->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(scan->object)->type)) return 0; } size = sizeof(TemplArg) * info->maxCount; savebuf = lalloc(size); for (scan = list; scan; scan = scan->next) { if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) { Object *obj; memcpy(savebuf, info->args, size); obj = OBJECT(scan->object); if (CTempl_DeduceType( arg->type, arg->qual & (Q_CONST | Q_VOLATILE), obj->type, obj->qual, savebuf, 1, 0 )) { memcpy(info->args, savebuf, size); return 1; } } } return 0; } Object *CTempl_DeduceFromFunctionCall(Object *funcobj, TemplArg *templargs, ENodeList *argexprs) { DeduceInfo info; FuncArg *arg; int i; CError_ASSERT(1655, IS_TEMPL_FUNC(funcobj->type)); if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, templargs, 0)) { arg = TYPE_FUNC(funcobj->type)->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(funcobj->type))) { CError_ASSERT(1664, arg); arg = arg->next; } while (1) { if (!arg || arg->type == &stvoid) { if (argexprs) return NULL; break; } if (arg == &elipsis) break; if (arg == &oldstyle) break; if (!argexprs) { if (arg->dexpr) break; return NULL; } ctempl_explicitargs_nindex = info.x12C; ctempl_explicitargs_num = info.count; ctempl_explicitargs_all = 1; if (CTempl_TypeNeedsDeduction(arg->type) && !ctempl_explicitargs_all) { ENode *node = argexprs->node; if (ENODE_IS(node, EOBJREF) && IS_TEMPL_FUNC(node->data.objref->type)) return NULL; if (ENODE_IS(node, EOBJLIST)) { if (!CExpr_DeduceFromObjList(arg, node->data.objlist.list, &info)) return NULL; } else { if (!CTempl_DeduceType( arg->type, arg->qual & (Q_CONST | Q_VOLATILE), node->rtype, ENODE_QUALS(node), info.args, 1, 0)) return NULL; } } argexprs = argexprs->next; arg = arg->next; } for (i = 0; i < info.maxCount; i++) { if (!info.args[i].is_deduced) return 0; info.args[i].next = &info.args[i + 1]; } info.args[info.maxCount].next = NULL; return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object; } else { return NULL; } } Object *CTempl_DeduceFromConversion(Object *funcobj, Type *type, UInt32 qual) { DeduceInfo info; int i; CError_ASSERT(1745, IS_TEMPL_FUNC(funcobj->type)); if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, NULL, 0)) return NULL; ctempl_explicitargs_nindex = info.x12C; ctempl_explicitargs_num = info.count; ctempl_explicitargs_all = 1; if (!CTempl_TypeNeedsDeduction(TYPE_FUNC(funcobj->type)->functype)) return NULL; if (!CTempl_DeduceType(TYPE_FUNC(funcobj->type)->functype, TYPE_FUNC(funcobj->type)->qual, type, qual, info.args, 0, 1)) return NULL; for (i = 0; i < info.maxCount; i++) { if (!info.args[i].is_deduced) return 0; info.args[i].next = &info.args[i + 1]; } info.args[info.maxCount].next = NULL; return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object; } static int CTemplFunc_TemplateNestLevel(NameSpace *nspace) { int level = 0; while (nspace) { if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_900)) level++; nspace = nspace->parent; } return level; } static Boolean CTemplFunc_SameFuncType(TypeFunc *a, TypeFunc *b) { FuncArg *arg1; FuncArg *arg2; CError_ASSERT(1800, IS_TYPE_FUNC(a) && IS_TYPE_FUNC(b)); if (!is_typesame(a->functype, b->functype)) return 0; if (a->qual != b->qual) return 0; if ((a->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000)) != (b->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000))) return 0; arg1 = a->args; if ((a->flags & FUNC_FLAGS_METHOD) && !TYPE_METHOD(a)->x26) { CError_ASSERT(1808, arg1); arg1 = arg1->next; } arg2 = b->args; if ((b->flags & FUNC_FLAGS_METHOD) && !TYPE_METHOD(b)->x26) { CError_ASSERT(1814, arg2); arg2 = arg2->next; } return is_arglistsame(arg1, arg2); } Object *CTempl_TemplateFunctionCheck(DeclInfo *di, NameSpaceObjectList *nsol) { TemplArg *arg; TemplFuncInstance *inst; Object *object; for (arg = di->expltargs; arg; arg = arg->next) { switch (arg->pid.type) { case TPT_TYPE: if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) break; continue; case TPT_NONTYPE: if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) break; continue; default: CError_FATAL(1844); } break; } if (arg) { while (nsol) { object = OBJECT(nsol->object); if ( object->otype == OT_OBJECT && IS_TEMPL_FUNC(object->type) && CTemplTool_IsSameTemplate(CTemplTool_GetFuncTempl(object)->params, di->expltargs) && CTemplFunc_SameFuncType(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(di->thetype)) ) return OBJECT(nsol->object); nsol = nsol->next; } } else { while (nsol) { object = OBJECT(nsol->object); if ( object->otype == OT_OBJECT && IS_TEMPL_FUNC(object->type) && (inst = CTempl_DeduceFunc(object, TYPE_FUNC(di->thetype), di->expltargs, NULL, 1)) ) { if (di->x3C) { if (!(di->qual & Q_INLINE)) { if (!inst->is_specialized) inst->object->qual &= ~Q_INLINE; } else { inst->object->qual |= Q_INLINE; } if (!inst->is_specialized && inst->is_instantiated) CError_Error(CErrorStr335); if (di->x3C != (CTemplFunc_TemplateNestLevel(inst->object->nspace) + 1)) CError_Warning(CErrorStr335); inst->is_specialized = 1; di->x3C = 0; } CTemplTool_MergeArgNames(TYPE_FUNC(di->thetype), TYPE_FUNC(inst->object->type)); di->x38 = CTemplTool_GetFuncTempl(OBJECT(nsol->object)); return inst->object; } nsol = nsol->next; } } CError_ResetErrorSkip(); CError_Error(CErrorStr335); di->x3C = 0; return NULL; }