#include "compiler/CTemplateTools.h" #include "compiler/CABI.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CExpr.h" #include "compiler/CFunc.h" #include "compiler/CInline.h" #include "compiler/CInt64.h" #include "compiler/CMachine.h" #include "compiler/CParser.h" #include "compiler/CScope.h" #include "compiler/CTemplateClass.h" #include "compiler/CTemplateNew.h" #include "compiler/CompilerTools.h" #include "compiler/enode.h" #include "compiler/objects.h" #include "compiler/scopes.h" #include "compiler/templates.h" #include "compiler/types.h" short ctempl_instdepth; void CTemplTool_PushInstance(TemplStack *stack, TypeClass *tmclass, Object *func) { if (tmclass) { stack->u.theclass = tmclass; stack->is_func = 0; } else { stack->u.func = func; stack->is_func = 1; } stack->next = ctempl_curinstance; ctempl_curinstance = stack; if (++ctempl_instdepth >= 64) CError_ErrorTerm(CErrorStr314); } void CTemplTool_PopInstance(TemplStack *stack) { CError_ASSERT(53, ctempl_curinstance == stack); ctempl_curinstance = stack->next; if (--ctempl_instdepth < 0) ctempl_instdepth = 0; } ENode *CTempTool_GetPTMTemplArgExpr(ENode *expr, Type *type) { NameSpaceObjectList *list; CError_ASSERT(69, ENODE_IS(expr, EMEMBER)); CError_ASSERT(70, IS_TYPE_MEMBERPOINTER(type)); if (!copts.cpp_extensions) { if (!expr->data.emember->x11 || !expr->data.emember->pr_1D) CError_Warning(CErrorStr331); } type = TYPE_MEMBER_POINTER(type)->ty1; for (list = expr->data.emember->list; list; list = list->next) { if (list->object->otype == OT_MEMBERVAR) { if (!is_typeequal(OBJ_MEMBER_VAR(list->object)->type, type)) CError_Error(CErrorStr146); return expr; } if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) { if (expr->data.emember->list != list || list->next) { // rewrite the EMEMBER to contain just one node expr->data.emember->list = galloc(sizeof(NameSpaceObjectList)); *expr->data.emember->list = *list; expr->data.emember->list->next = NULL; } break; } } if (!list) CError_Error(CErrorStr146); return expr; } Boolean CTemplTool_InitDeduceInfo(DeduceInfo *info, TemplParam *params, TemplArg *args, Boolean flag) { int i; TemplArg *buffer; TemplParam *param; if (!params) { info->args = info->argBuffer; info->maxCount = 0; info->x12C = 0xFF; return 1; } memclrw(info, sizeof(DeduceInfo)); i = 0; param = params; while (param) { param = param->next; i++; } if (i > 16) { buffer = lalloc(i * sizeof(TemplArg)); memclrw(buffer, i * sizeof(TemplArg)); } else { buffer = info->argBuffer; } info->args = buffer; info->maxCount = i; info->x12C = params->pid.nindex; for (param = params, i = 0; param; param = param->next, i++) buffer[i].pid = param->pid; i = 0; param = params; while (args) { if (!param || param->pid.type != args->pid.type) return 0; buffer[i].data = args->data; if (i > 0) buffer[i - 1].next = &buffer[i]; buffer[i].next = NULL; buffer[i].is_deduced = 1; info->count++; if (param->pid.type == TPT_NONTYPE && !CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) { if (CExpr_CanImplicitlyConvert(buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual)) { buffer[i].data.paramdecl.expr = CExpr_AssignmentPromotion( buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual, 0); } else { return 0; } } args = args->next; param = param->next; i++; } if (flag) { for (param = params, i = 0; param; param = param->next, i++) { if (!buffer[i].is_deduced && !param->name) { switch (param->pid.type) { case TPT_TYPE: buffer[i].data.typeparam.type = &stvoid; break; case TPT_NONTYPE: buffer[i].data.paramdecl.expr = nullnode(); break; case TPT_TEMPLATE: default: CError_FATAL(208); } buffer[i].is_deduced = 1; } } } return 1; } void CTemplTool_InsertTemplateParameter(NameSpace *nspace, TemplParam *param) { Type *type; ObjType *obj; NameSpaceName *nsn; type = CDecl_NewTemplDepType(TEMPLDEP_ARGUMENT); TYPE_TEMPLATE(type)->u.pid = param->pid; obj = galloc(sizeof(ObjType)); memclrw(obj, sizeof(ObjType)); obj->otype = OT_TYPE; obj->access = ACCESSPUBLIC; obj->type = type; for (nsn = nspace->tparams; nsn; nsn = nsn->next) { if (nsn->name == param->name) { CError_Error(CErrorStr122, param->name->name); return; } } nsn = galloc(sizeof(NameSpaceName)); memclrw(nsn, sizeof(NameSpaceName)); nsn->name = param->name; nsn->first.object = OBJ_BASE(obj); nsn->next = nspace->tparams; nspace->tparams = nsn; } TemplArg *CTemplTool_MakeTemplArgList(DeduceInfo *info) { TemplArg *args; TemplArg *last; int i; for (i = 0; i < info->maxCount; i++) { if (i) { last->next = galloc(sizeof(TemplArg)); last = last->next; } else { args = last = galloc(sizeof(TemplArg)); } *last = info->args[i]; } last->next = NULL; return args; } Boolean CTemplTool_IsIdenticalTemplArgList(TemplArg *args, TemplParam *params) { while (args) { if (!params) return 0; CError_ASSERT(297, params->pid.type == args->pid.type); switch (args->pid.type) { case TPT_TYPE: if ( !IS_TYPE_TEMPLATE(args->data.typeparam.type) || TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT || TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index || TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex ) return 0; break; case TPT_NONTYPE: if ( !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) || args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM || args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index || args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex ) return 0; break; case TPT_TEMPLATE: if ( !IS_TYPE_TEMPLATE(args->data.ttargtype) || TYPE_TEMPLATE(args->data.ttargtype)->dtype != TEMPLDEP_ARGUMENT || TYPE_TEMPLATE(args->data.ttargtype)->u.pid.index != params->pid.index || TYPE_TEMPLATE(args->data.ttargtype)->u.pid.nindex != params->pid.nindex ) return 0; break; default: CError_FATAL(331); } args = args->next; params = params->next; } return !params; } Type *CTemplTool_GetSelfRefTemplate(Type *type) { TemplClass *templ; TemplArg *args; CError_ASSERT(347, IS_TYPE_TEMPLATE(type)); if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_TEMPLATE) { if (CTemplTool_IsIdenticalTemplArgList( TYPE_TEMPLATE(type)->u.templ.args, TYPE_TEMPLATE(type)->u.templ.templ->templ__params)) return TYPE(TYPE_TEMPLATE(type)->u.templ.templ); if (TYPE_TEMPLATE(type)->u.templ.templ->pspecs) { templ = TYPE_TEMPLATE(type)->u.templ.templ; if ( CTemplClass_FindPartialTemplate(TYPE_TEMPLATE(type)->u.templ.args, &templ, &args) && CTemplTool_IsIdenticalTemplArgList(args, templ->templ__params) ) return TYPE(templ); } return NULL; } if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME) { Type *t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type)); if ( t && (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(type)->u.qual.name)) && IS_TEMPL_CLASS(t) && !TEMPL_CLASS(t)->templ__params ) return t; return NULL; } if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALTEMPL) { Type *t; CError_ASSERT(389, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->dtype == TEMPLDEP_QUALNAME); t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.type)); if ( t && (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.name)) && IS_TEMPL_CLASS(t) ) { TemplClass *tm = TEMPL_CLASS(t); if (CTemplTool_IsIdenticalTemplArgList(TYPE_TEMPLATE(type)->u.qualtempl.args, tm->templ__params)) return TYPE(tm); } } return NULL; } TemplateFunction *CTemplTool_GetFuncTempl(Object *object) { while (object->datatype == DALIAS) object = object->u.alias.object; CError_ASSERT(416, IS_TEMPL_FUNC(object->type)); return object->u.func.u.templ; } Boolean CTemplTool_ParamHasDefaultArg(TemplParam *param) { switch (param->pid.type) { case TPT_TYPE: return param->data.typeparam.type != NULL; case TPT_NONTYPE: return param->data.paramdecl.defaultarg != NULL; case TPT_TEMPLATE: default: CError_FATAL(438); return 0; } } void CTemplTool_MergeDefaultArgs(TemplParam *dest, TemplParam *src) { while (1) { if (!dest) { CError_ASSERT(455, !src); return; } CError_ASSERT(458, src); CError_ASSERT(459, dest->pid.type == src->pid.type); switch (dest->pid.type) { case TPT_TYPE: if (!dest->data.typeparam.type && src->data.typeparam.type) dest->data = src->data; break; case TPT_NONTYPE: if (!dest->data.paramdecl.defaultarg && src->data.paramdecl.defaultarg) dest->data = src->data; break; case TPT_TEMPLATE: if (!dest->data.templparam.defaultarg && src->data.templparam.defaultarg) dest->data = src->data; break; default: CError_FATAL(484); } dest = dest->next; src = src->next; } } static FuncArg *CTemplTool_GetFirstRealArg(TypeFunc *tfunc) { FuncArg *arg = tfunc->args; if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc)) { CError_ASSERT(502, arg); arg = arg->next; if ((tfunc->flags & FUNC_IS_CTOR) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_HAS_VBASES)) { CError_ASSERT(507, arg); arg = arg->next; } } return arg; } void CTemplTool_MergeArgNames(TypeFunc *src, TypeFunc *dest) { FuncArg *destArg; FuncArg *srcArg; CError_ASSERT(524, IS_TYPE_FUNC(dest) && IS_TYPE_FUNC(src)); srcArg = CTemplTool_GetFirstRealArg(src); destArg = CTemplTool_GetFirstRealArg(dest); while (1) { if (!srcArg || !destArg || srcArg == &elipsis || destArg == &elipsis) { CError_ASSERT(531, srcArg == destArg); break; } destArg->name = srcArg->name; srcArg = srcArg->next; destArg = destArg->next; } if (IS_TYPEFUNC_NONSTATIC_METHOD(dest)) { CError_ASSERT(538, destArg = dest->args); if (!destArg->name) destArg->name = this_name_node; } } Boolean CTemplTool_EqualParams(TemplParam *a, TemplParam *b, Boolean copyNames) { while (1) { if (!a) return !b; if (!b) return 0; if (a->pid.type != b->pid.type) return 0; if (copyNames) a->name = b->name; switch (a->pid.type) { case TPT_TYPE: break; case TPT_NONTYPE: if ( !is_typesame(a->data.paramdecl.type, b->data.paramdecl.type) || a->data.paramdecl.qual != b->data.paramdecl.qual ) return 0; break; case TPT_TEMPLATE: break; default: CError_FATAL(576); } a = a->next; b = b->next; } } NameSpace *CTemplTool_SetupTemplateArgumentNameSpace(TemplParam *params, TemplArg *args, Boolean is_global) { NameSpace *nspace; Boolean clear_global; ObjType *objType; Object *object; clear_global = 0; if (!is_global && trychain) { clear_global = 1; is_global = 1; } nspace = CScope_NewListNameSpace(NULL, is_global); nspace->is_templ = 1; if (clear_global) nspace->is_global = 0; if (!params) return nspace; while (params) { CError_ASSERT(607, args); if (params->name) { switch (args->pid.type) { case TPT_TYPE: if (is_global) { objType = galloc(sizeof(ObjType)); memclrw(objType, sizeof(ObjType)); } else { objType = lalloc(sizeof(ObjType)); memclrw(objType, sizeof(ObjType)); } objType->otype = OT_TYPE; objType->access = ACCESSPUBLIC; objType->type = args->data.typeparam.type; objType->qual = args->data.typeparam.qual; CScope_AddObject(nspace, params->name, OBJ_BASE(objType)); break; case TPT_NONTYPE: if (is_global) { object = galloc(sizeof(Object)); memclrw(object, sizeof(Object)); } else { object = lalloc(sizeof(Object)); memclrw(object, sizeof(Object)); } object->otype = OT_OBJECT; object->access = ACCESSPUBLIC; object->nspace = nspace; object->name = params->name; object->type = args->data.paramdecl.expr->rtype; object->qual = ENODE_QUALS(args->data.paramdecl.expr); object->datatype = DEXPR; object->u.expr = args->data.paramdecl.expr; if (IS_TYPE_REFERENCE(params->data.paramdecl.type)) { CError_ASSERT(652, IS_TYPE_POINTER_ONLY(object->u.expr->rtype)); object->u.expr = makemonadicnode(object->u.expr, EINDIRECT); object->u.expr->rtype = TPTR_TARGET(params->data.paramdecl.type); } if (is_global) object->u.expr = CInline_CopyExpression(object->u.expr, CopyMode1); CScope_AddObject(nspace, params->name, OBJ_BASE(object)); break; case TPT_TEMPLATE: if (is_global) { objType = galloc(sizeof(ObjType)); memclrw(objType, sizeof(ObjType)); } else { objType = lalloc(sizeof(ObjType)); memclrw(objType, sizeof(ObjType)); } objType->otype = OT_TYPE; objType->access = ACCESSPUBLIC; objType->type = args->data.ttargtype; objType->qual = 0; CScope_AddObject(nspace, params->name, OBJ_BASE(objType)); break; default: CError_FATAL(681); } } params = params->next; args = args->next; } CError_ASSERT(685, !args); return nspace; } void CTemplTool_SetupOuterTemplateArgumentNameSpace(NameSpace *nspace) { NameSpace *newns; while (nspace) { if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST)) { newns = CTemplTool_SetupTemplateArgumentNameSpace( TEMPL_CLASS_INST(nspace->theclass)->templ->templ__params, TEMPL_CLASS_INST(nspace->theclass)->inst_args, 0); newns->parent = nspace->parent; nspace->parent = newns; } nspace = nspace->parent; } } NameSpace *CTemplTool_InsertTemplateArgumentNameSpace(TemplParam *params, TemplClassInst *inst, CScopeSave *save) { NameSpace *nspace = CTemplTool_SetupTemplateArgumentNameSpace(params, inst->inst_args, 0); nspace->parent = inst->theclass.nspace->parent; inst->theclass.nspace->parent = nspace; CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace); CScope_SetNameSpaceScope(inst->theclass.nspace, save); return nspace; } void CTemplTool_RemoveOuterTemplateArgumentNameSpace(NameSpace *nspace) { while (nspace->parent) { if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST) && nspace->parent->is_templ) nspace->parent = nspace->parent->parent; nspace = nspace->parent; } } void CTemplTool_RemoveTemplateArgumentNameSpace(NameSpace *nspace, TemplClassInst *inst, CScopeSave *save) { CTemplTool_RemoveOuterTemplateArgumentNameSpace(inst->theclass.nspace); CScope_RestoreScope(save); } Boolean CTemplTool_IsTemplateArgumentDependentType(Type *type) { FuncArg *arg; while (1) { switch (type->type) { case TYPETEMPLATE: return 1; case TYPEVOID: case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPESTRUCT: return 0; case TYPECLASS: return (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL) ? 1 : 0; case TYPEMEMBERPOINTER: if (CTemplTool_IsTemplateArgumentDependentType(TYPE_MEMBER_POINTER(type)->ty1)) return 1; type = TYPE_MEMBER_POINTER(type)->ty2; continue; case TYPEPOINTER: case TYPEARRAY: type = TPTR_TARGET(type); continue; case TYPEFUNC: for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis && arg != &oldstyle; arg = arg->next) { if (CTemplTool_IsTemplateArgumentDependentType(arg->type)) return 1; } type = TYPE_FUNC(type)->functype; continue; case TYPEBITFIELD: type = TYPE_BITFIELD(type)->bitfieldtype; continue; case TYPETEMPLDEPEXPR: return 1; default: CError_FATAL(822); } } } Boolean CTemplTool_IsTemplateArgumentDependentExpression(ENode *expr) { if (!expr) return 0; if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) return 1; return 0; } Boolean CTemplTool_IsSameTemplate(TemplParam *params, TemplArg *args) { while (1) { if (!args) { CError_ASSERT(850, !params); return 1; } CError_ASSERT(853, params && args->pid.type == params->pid.type); switch (args->pid.type) { case TPT_TYPE: if ( !IS_TYPE_TEMPLATE(args->data.typeparam.type) || TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT || TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex || TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index || args->data.typeparam.qual != 0 ) return 0; break; case TPT_NONTYPE: if ( !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) || args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM || args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex || args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index ) return 0; break; case TPT_TEMPLATE: if (!IS_TYPE_TEMPLATE(args->data.ttargtype)) return 0; break; default: CError_FATAL(886); } args = args->next; params = params->next; } } TemplClass *CTemplTool_IsTemplate(TypeTemplDep *ttd) { if (ttd->dtype == TEMPLDEP_QUALNAME && ttd->u.qual.type->dtype == TEMPLDEP_TEMPLATE) ttd = ttd->u.qual.type; else if (ttd->dtype != TEMPLDEP_TEMPLATE) return NULL; if (CTemplTool_IsSameTemplate(ttd->u.templ.templ->templ__params, ttd->u.templ.args)) return ttd->u.templ.templ; else return NULL; } Type *CTemplTool_IsDependentTemplate(TemplClass *tmclass, TemplArg *args) { TemplParam *param; TemplArg *arg; Type *type; if (!tmclass->templ_parent || tmclass->inst_parent) { arg = args; param = tmclass->templ__params; while (1) { if (!arg) { CError_ASSERT(988, !param); return NULL; } CError_ASSERT(991, param && arg->pid.type == param->pid.type); switch (arg->pid.type) { case TPT_TYPE: if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) goto done; break; case TPT_NONTYPE: if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) goto done; break; case TPT_TEMPLATE: if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype)) goto done; break; default: CError_FATAL(1008); goto done; } arg = arg->next; param = param->next; } } done: if (cscope_current->theclass == TYPE_CLASS(tmclass) && CTemplTool_IsSameTemplate(tmclass->templ__params, args)) return TYPE(tmclass); type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE); TYPE_TEMPLATE(type)->u.templ.templ = tmclass; TYPE_TEMPLATE(type)->u.templ.args = args; return type; } Boolean CTemplTool_EqualExprTypes(ENode *a, ENode *b) { Object *objA; Object *objB; if (!a || !b) return 0; if (a->type != b->type) return 0; switch (a->type) { case EINTCONST: return CInt64_Equal(a->data.intval, b->data.intval); case EOBJREF: objA = a->data.objref; while (objA->datatype == DALIAS) objA = objA->u.alias.object; objB = b->data.objref; while (objB->datatype == DALIAS) objB = objB->u.alias.object; return objA == objB; case EMEMBER: return a->data.emember->list == b->data.emember->list; case ETEMPLDEP: if (a->data.templdep.subtype != b->data.templdep.subtype) return 0; switch (a->data.templdep.subtype) { case TDE_PARAM: return a->data.templdep.u.pid.nindex == b->data.templdep.u.pid.nindex && a->data.templdep.u.pid.index == b->data.templdep.u.pid.index; case TDE_SIZEOF: case TDE_ALIGNOF: return is_typesame(a->data.templdep.u.typeexpr.type, b->data.templdep.u.typeexpr.type); case TDE_CAST: return is_typesame(a->data.templdep.u.cast.type, b->data.templdep.u.cast.type) && a->data.templdep.u.cast.qual == b->data.templdep.u.cast.qual; case TDE_QUALNAME: return is_typesame(TYPE(a->data.templdep.u.qual.type), TYPE(b->data.templdep.u.qual.type)) && a->data.templdep.u.qual.name == b->data.templdep.u.qual.name; case TDE_OBJ: return a->data.templdep.u.obj == b->data.templdep.u.obj; case TDE_ADDRESS_OF: return CTemplTool_EqualExprTypes(a->data.templdep.u.monadic, b->data.templdep.u.monadic); default: CError_FATAL(1086); } case EMUL: case EDIV: case EMODULO: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EROTL: case EROTR: return CTemplTool_EqualExprTypes(a->data.diadic.left, b->data.diadic.left) && CTemplTool_EqualExprTypes(a->data.diadic.right, b->data.diadic.right); case EMONMIN: case EBINNOT: case ELOGNOT: return CTemplTool_EqualExprTypes(a->data.monadic, b->data.monadic); case ECOND: return CTemplTool_EqualExprTypes(a->data.cond.cond, b->data.cond.cond) && CTemplTool_EqualExprTypes(a->data.cond.expr1, b->data.cond.expr1) && CTemplTool_EqualExprTypes(a->data.cond.expr2, b->data.cond.expr2); default: CError_FATAL(1122); return 0; } } ENode *CTempl_MakeTemplDepExpr(ENode *left, ENodeType nt, ENode *right) { if (!IS_TYPE_TEMPLDEPEXPR(right->rtype)) { right = pointer_generation(right); if (!ENODE_IS(right, EINTCONST)) { CError_Error(CErrorStr348); right = nullnode(); } } if (left) { if (!IS_TYPE_TEMPLDEPEXPR(left->rtype)) { left = pointer_generation(left); if (!ENODE_IS(left, EINTCONST)) { CError_Error(CErrorStr348); left = nullnode(); } } left = makediadicnode(left, right, nt); } else { left = makemonadicnode(right, nt); } left->rtype = &sttemplexpr; return left; } void CTemplTool_CheckTemplArgType(Type *type) { while (IS_TYPE_POINTER_ONLY(type)) type = TPTR_TARGET(type); if (IS_TYPE_CLASS(type)) { if (IsTempName(TYPE_CLASS(type)->classname) || CScope_IsInLocalNameSpace(TYPE_CLASS(type)->nspace)) CError_Error(CErrorStr232); } } Boolean CTemplTool_EqualArgs(TemplArg *a, TemplArg *b) { while (a) { if (!b || a->pid.type != b->pid.type) return 0; switch (a->pid.type) { case TPT_TYPE: if ( !is_typesame(a->data.typeparam.type, b->data.typeparam.type) || a->data.typeparam.qual != b->data.typeparam.qual ) return 0; break; case TPT_NONTYPE: if (!CTemplTool_EqualExprTypes(a->data.paramdecl.expr, b->data.paramdecl.expr)) return 0; break; case TPT_TEMPLATE: if (!is_typesame(a->data.ttargtype, b->data.ttargtype)) return 0; break; default: CError_FATAL(1215); } a = a->next; b = b->next; } if (b) return 0; return 1; } TemplArg *CTemplTool_MakeGlobalTemplArgCopy(TemplArg *args) { TemplArg *firstCopy; TemplArg *copy; firstCopy = NULL; while (args) { if (firstCopy) { copy->next = galloc(sizeof(TemplArg)); copy = copy->next; } else { copy = galloc(sizeof(TemplArg)); firstCopy = copy; } *copy = *args; if (copy->pid.type == TPT_NONTYPE && copy->data.paramdecl.expr) copy->data.paramdecl.expr = CInline_CopyExpression(copy->data.paramdecl.expr, CopyMode1); args = args->next; } return firstCopy; } Boolean CTemplTool_TemplDepTypeCompare(TypeTemplDep *a, TypeTemplDep *b) { if (a == b) return 1; if (a->dtype != b->dtype) return 0; switch (a->dtype) { case TEMPLDEP_ARGUMENT: return a->u.pid.nindex == b->u.pid.nindex && a->u.pid.index == b->u.pid.index; case TEMPLDEP_QUALNAME: return CTemplTool_TemplDepTypeCompare(a->u.qual.type, b->u.qual.type) && a->u.qual.name == b->u.qual.name; case TEMPLDEP_TEMPLATE: return a->u.templ.templ == b->u.templ.templ && CTemplTool_EqualArgs(a->u.templ.args, b->u.templ.args); case TEMPLDEP_ARRAY: return is_typesame(a->u.array.type, b->u.array.type) && CTemplTool_EqualExprTypes(a->u.array.index, b->u.array.index); case TEMPLDEP_QUALTEMPL: return CTemplTool_TemplDepTypeCompare(a->u.qualtempl.type, b->u.qualtempl.type) && CTemplTool_EqualArgs(a->u.qualtempl.args, b->u.qualtempl.args); case TEMPLDEP_BITFIELD: return is_typesame(a->u.bitfield.type, b->u.bitfield.type) && CTemplTool_EqualExprTypes(a->u.bitfield.size, b->u.bitfield.size); default: CError_FATAL(1286); return 0; } } Type *CTemplTool_DeduceArgDepType(TemplArg *args, Type *type, UInt32 qual, UInt32 *resultQual) { TemplArg *arg; *resultQual = qual; if (IS_TYPE_TEMPLATE(type) && TYPE_TEMPLATE(type)->dtype == TEMPLDEP_ARGUMENT) { arg = args; while (1) { if (!arg) return NULL; if ( arg->pid.index == TYPE_TEMPLATE(type)->u.pid.index && arg->pid.nindex == TYPE_TEMPLATE(type)->u.pid.nindex ) break; arg = arg->next; } CError_ASSERT(1314, arg->pid.type == TPT_TYPE); *resultQual |= arg->data.typeparam.qual; return arg->data.typeparam.type; } return NULL; } static TemplClassInst *CTemplTool_FindNestedClassInstance(TemplClass *a, TemplClass *b, TemplClassInst *c) { TemplClass *array[32]; TemplClassInst *inst; int i; array[0] = a; i = 0; while (1) { CError_ASSERT(1338, i < 32); CError_ASSERT(1339, a = a->templ_parent); if (a == b) break; CError_ASSERT(1341, a->templ__params == NULL); array[++i] = a; } while (1) { inst = array[i--]->instances; while (1) { CError_ASSERT(1350, inst); if (inst->parent == c) break; inst = inst->next; } c = inst; if (i < 0) break; if ((inst->theclass.flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) CTempl_InstantiateTemplateClass(TYPE_CLASS(inst)); } return inst; } static TemplClassInst *CTemplTool_FindNestedClass(TemplClass *a, TemplClassInst *b, TemplClass *c) { TemplClass *scan; while (1) { for (scan = c->templ_parent; scan; scan = scan->templ_parent) { if (scan == a) return CTemplTool_FindNestedClassInstance(c, a, b); } a = a->templ_parent; if (!a) break; b = b->parent; CError_ASSERT(1377, b); } return NULL; } static Type *CTemplTool_FindTemplateInstance(TypeDeduce *deduce, TemplClass *templ) { TemplClass *scantempl; TemplClass *dtempl; TemplClassInst *scaninst; TemplClassInst *dinst; dtempl = deduce->tmclass; CError_ASSERT(1393, dtempl); dinst = deduce->inst; if (!dinst) { if (!dtempl->templ_parent || !dtempl->inst_parent) return TYPE(templ); dtempl = dtempl->templ_parent; dinst = deduce->tmclass->inst_parent; } scantempl = dtempl; scaninst = dinst; while (1) { if (scantempl == templ) return TYPE(scaninst); if (!scantempl->templ_parent && scantempl->pspec_owner) scantempl = scantempl->pspec_owner; scantempl = scantempl->templ_parent; if (!scantempl) break; CError_ASSERT(1416, scaninst = scaninst->parent); } if (dtempl->flags & TEMPLCLASS_FLAGS_2) { scantempl = TEMPL_CLASS(dtempl->theclass.nspace->theclass); CError_ASSERT(1422, scantempl->theclass.flags & CLASS_IS_TEMPL); scaninst = dinst; while (1) { if (scantempl == templ) return TYPE(scaninst); scantempl = scantempl->templ_parent; if (!scantempl) break; CError_ASSERT(1430, scaninst = scaninst->parent); } } if (!templ->templ__params && (scaninst = CTemplTool_FindNestedClass(dtempl, dinst, templ))) return TYPE(scaninst); CError_FATAL(1477); return NULL; } static ENode *CTemplTool_DeduceExprCheck(ENode *expr) { if (expr->type != EINTCONST) { CError_Error(CErrorStr348); expr = nullnode(); } return expr; } static ENodeList *CTemplTool_DeduceExprList(TypeDeduce *deduce, ENodeList *list) { ENodeList *resultList; ENodeList *last; resultList = NULL; while (list) { if (resultList) { last->next = lalloc(sizeof(ENodeList)); last = last->next; } else { last = lalloc(sizeof(ENodeList)); resultList = last; } *last = *list; last->node = CTemplTool_DeduceExpr(deduce, last->node); list = list->next; } return resultList; } ENode *CTemplTool_DeduceExpr(TypeDeduce *deduce, ENode *expr) { TemplArg *arg; TemplClassInst *inst; ENode *newExpr; NameSpaceObjectList *nsObjectList; TStreamElement *saved; NameResult pr; Type *type; UInt32 qual; if (!CTemplTool_IsTemplateArgumentDependentExpression(expr)) { newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; return newExpr; } switch (expr->type) { case ETEMPLDEP: switch (expr->data.templdep.subtype) { case TDE_PARAM: if (deduce->x15 && expr->data.templdep.u.pid.nindex == deduce->nindex) { newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; return newExpr; } for (arg = deduce->args; arg; arg = arg->next) { if ( arg->pid.index == expr->data.templdep.u.pid.index && arg->pid.nindex == expr->data.templdep.u.pid.nindex ) { CError_ASSERT(1562, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr); newExpr = lalloc(sizeof(ENode)); *newExpr = *arg->data.paramdecl.expr; return newExpr; } } for (inst = deduce->inst; inst; inst = inst->parent) { for (arg = inst->inst_args; arg; arg = arg->next) { if ( arg->pid.index == expr->data.templdep.u.pid.index && arg->pid.nindex == expr->data.templdep.u.pid.nindex ) { CError_ASSERT(1575, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr); newExpr = lalloc(sizeof(ENode)); *newExpr = *arg->data.paramdecl.expr; return newExpr; } } } CError_FATAL(1582); case TDE_SIZEOF: qual = 0; type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual); CDecl_CompleteType(type); if (CTemplTool_IsTemplateArgumentDependentType(type)) { newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; newExpr->data.templdep.u.typeexpr.type = type; return newExpr; } return intconstnode(CABI_GetSizeTType(), type->size); case TDE_ALIGNOF: qual = 0; type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual); CDecl_CompleteType(type); if (CTemplTool_IsTemplateArgumentDependentType(type)) { newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; newExpr->data.templdep.u.typeexpr.type = type; return newExpr; } return intconstnode(CABI_GetSizeTType(), CMach_GetTypeAlign(type)); case TDE_CAST: qual = expr->data.templdep.u.cast.qual; type = CTemplTool_DeduceTypeCopy(deduce, expr->data.templdep.u.cast.type, &qual); return CExpr_DoExplicitConversion(type, qual, CTemplTool_DeduceExprList(deduce, expr->data.templdep.u.cast.args)); case TDE_QUALNAME: qual = 0; type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.qual.type), &qual); if (IS_TYPE_CLASS(type)) { CDecl_CompleteType(type); if (CScope_FindQualifiedClassMember(&pr, TYPE_CLASS(type), expr->data.templdep.u.qual.name)) return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr)); CError_Error(CErrorStr150, expr->data.templdep.u.qual.name->name); } else if (IS_TYPE_TEMPLATE(type) && !deduce->inst) { newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; newExpr->data.templdep.u.qual.type = TYPE_TEMPLATE(type); return newExpr; } else { CError_Error(CErrorStr340, expr->data.templdep.u.qual.name->name); } return nullnode(); case TDE_OBJ: type = CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(expr->data.templdep.u.obj->nspace->theclass)); CError_ASSERT(1651, type && IS_TYPE_CLASS(type)); nsObjectList = CScope_GetLocalObject(TYPE_CLASS(type)->nspace, expr->data.templdep.u.obj->name); CError_ASSERT(1654, nsObjectList); memclrw(&pr, sizeof(pr)); pr.obj_10 = nsObjectList->object; return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr)); case TDE_SOURCEREF: CError_LockErrorPos(expr->data.templdep.u.sourceref.token, &saved); newExpr = CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.sourceref.expr); CError_UnlockErrorPos(&saved); return newExpr; case TDE_ADDRESS_OF: return getnodeaddress(CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.monadic), 1); default: CError_FATAL(1671); } case EFUNCCALL: newExpr = CExpr_PointerGeneration(CTemplTool_DeduceExpr(deduce, expr->data.funccall.funcref)); return CExpr_MakeFunctionCall(newExpr, CTemplTool_DeduceExprList(deduce, expr->data.funccall.args)); case ELOGNOT: return CExpr_New_ELOGNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); case EMONMIN: return CExpr_New_EMONMIN_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); case EBINNOT: return CExpr_New_EBINNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); case EMUL: case EDIV: case EMODULO: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EROTL: case EROTR: return CExpr_NewDyadicNode( CTemplTool_DeduceExpr(deduce, expr->data.diadic.left), expr->type, CTemplTool_DeduceExpr(deduce, expr->data.diadic.right)); case ECOND: return CExpr_New_ECOND_Node( CTemplTool_DeduceExpr(deduce, expr->data.cond.cond), CTemplTool_DeduceExpr(deduce, expr->data.cond.expr1), CTemplTool_DeduceExpr(deduce, expr->data.cond.expr2)); default: CError_FATAL(1727); case EINTCONST: newExpr = lalloc(sizeof(ENode)); *newExpr = *expr; return newExpr; } } ENode *CTemplTool_DeduceDefaultArg(Object *func, ENode *expr) { TypeDeduce deduce; memclrw(&deduce, sizeof(deduce)); CError_ASSERT(1747, IS_TYPE_FUNC(func->type)); if (func->u.func.inst) deduce.args = func->u.func.inst->args; if ((TYPE_FUNC(func->type)->flags & FUNC_METHOD) && (TYPE_METHOD(func->type)->theclass->flags & CLASS_IS_TEMPL_INST)) { deduce.inst = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass); deduce.tmclass = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass)->templ; } return CTemplTool_DeduceExpr(&deduce, expr); } static TemplClass *CTemplTool_FindNestedTemplateInstance(TypeDeduce *deduce, TemplClass *templ) { TemplClass *dtempl; TemplClassInst *dinst; Type *type; if (templ->inst_parent) return templ; CError_ASSERT(1776, (dtempl = deduce->tmclass) && (dinst = deduce->inst)); while (1) { if ( templ->templ_parent == dtempl && (type = CScope_GetLocalTagType(dinst->theclass.nspace, templ->theclass.classname)) && IS_TEMPL_CLASS(type) && TEMPL_CLASS(type)->templ_parent == templ->templ_parent ) return TEMPL_CLASS(type); dtempl = dtempl->templ_parent; if (!dtempl) break; dinst = dinst->parent; CError_ASSERT(1790, dinst); } return templ; } static Type *CTemplTool_DeduceClassInstanceCopy(TypeDeduce *deduce, TemplClass *templ, TemplArg *args) { TemplArg *arg; TemplArg *deducedArgs; TemplArg *last; TemplParam *param; UInt32 qual; Type *type; if (templ->templ_parent) templ = CTemplTool_FindNestedTemplateInstance(deduce, templ); arg = args; deducedArgs = NULL; param = templ->templ__params; while (arg) { if (deducedArgs) { last->next = galloc(sizeof(TemplArg)); last = last->next; } else { last = galloc(sizeof(TemplArg)); deducedArgs = last; } *last = *arg; if (!param || param->pid.type != last->pid.type) { CError_Error(CErrorStr374); return &stvoid; } last->pid = param->pid; param = param->next; switch (last->pid.type) { case TPT_TYPE: last->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, last->data.typeparam.type, &last->data.typeparam.qual); break; case TPT_NONTYPE: if (!last->data.paramdecl.expr) { CError_FATAL(1873); } else if (CTemplTool_IsTemplateArgumentDependentExpression(last->data.paramdecl.expr)) { last->data.paramdecl.expr = pointer_generation(CTemplTool_DeduceExpr(deduce, last->data.paramdecl.expr)); last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1); } break; case TPT_TEMPLATE: qual = 0; last->data.ttargtype = CTemplTool_DeduceTypeCopy(deduce, last->data.ttargtype, &qual); break; default: CError_FATAL(1891); } arg = arg->next; } for (arg = deducedArgs; 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; switch (arg->data.paramdecl.expr->type) { case EINTCONST: case EOBJLIST: case EMEMBER: break; case EOBJREF: if (CParser_HasInternalLinkage2(arg->data.paramdecl.expr->data.objref)) CError_Error(CErrorStr357); break; default: CError_Error(CErrorStr371); arg->data.paramdecl.expr = nullnode(); break; } continue; case TPT_TEMPLATE: if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype)) break; continue; default: CError_FATAL(1937); } break; } if (arg) { type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE); TYPE_TEMPLATE(type)->u.templ.templ = templ; TYPE_TEMPLATE(type)->u.templ.args = deducedArgs; return type; } if ((type = CTemplTool_IsDependentTemplate(templ, deducedArgs))) return type; return TYPE(CTemplClass_GetInstance(templ, deducedArgs, NULL)); } static TemplArg *CTemplTool_FindTemplArg(TemplArg *args, TemplParamID pid) { while (args) { if (args->pid.index == pid.index && args->pid.nindex == pid.nindex) { CError_ASSERT(1984, pid.type == args->pid.type); return args; } args = args->next; } return NULL; } static TemplArg *CTemplTool_DeduceTemplArg(TypeDeduce *deduce, TemplParamID pid) { TemplClass *tmclass; TemplClassInst *inst; TemplArg *arg; if ((arg = CTemplTool_FindTemplArg(deduce->args, pid))) return arg; tmclass = deduce->tmclass; CError_ASSERT(2008, tmclass); inst = deduce->inst; if (!inst) { CError_ASSERT(2011, tmclass->templ_parent && tmclass->inst_parent); inst = deduce->tmclass->inst_parent; } while (1) { if ((arg = CTemplTool_FindTemplArg(inst->inst_args, pid))) return arg; inst = inst->parent; CError_ASSERT(2022, inst); } } static Type *CTemplTool_DeduceArrayCopy(TypeDeduce *deduce, Type *type, ENode *index, UInt32 *resultQual) { if (CTemplTool_IsTemplateArgumentDependentType(type)) type = CTemplTool_DeduceTypeCopy(deduce, type, resultQual); index = CTemplTool_DeduceExpr(deduce, index); if (ENODE_IS(index, EINTCONST)) { if (CInt64_IsNegative(&index->data.intval)) { CError_Error(CErrorStr124); index->data.intval = cint64_one; } if (!CDecl_CheckArrayIntegr(type)) type = TYPE(&stsignedchar); type = CDecl_NewArrayType(type, type->size * CInt64_GetULong(&index->data.intval)); } else { if (!deduce->x16) CError_Error(CErrorStr124); } return type; } static Type *CTemplTool_DeduceBitfieldCopy(TypeDeduce *deduce, Type *type, ENode *size, UInt32 *resultQual) { TypeBitfield *tbitfield; short sizeval; short maxsize; if (CTemplTool_IsTemplateArgumentDependentType(type)) { UInt32 qual = 0; type = CTemplTool_DeduceTypeCopy(deduce, type, &qual); } if (!IS_TYPE_INT_OR_ENUM(type)) { CError_Error(CErrorStr138); type = TYPE(&stunsignedint); } switch (type->size) { case 1: maxsize = 8; break; case 2: maxsize = 16; break; case 4: maxsize = 32; break; default: CError_Error(CErrorStr138); return type; } if (!ENODE_IS(size, EINTCONST)) { size = CTemplTool_DeduceExpr(deduce, size); if (!ENODE_IS(size, EINTCONST)) { CError_Error(CErrorStr124); return type; } } sizeval = CInt64_GetULong(&size->data.intval); if (sizeval > maxsize || CInt64_IsNegative(&size->data.intval)) { CError_Error(CErrorStr138); sizeval = 1; } tbitfield = galloc(sizeof(TypeBitfield)); memclrw(tbitfield, sizeof(TypeBitfield)); tbitfield->type = TYPEBITFIELD; tbitfield->size = type->size; tbitfield->bitfieldtype = type; tbitfield->bitlength = sizeval; return TYPE(tbitfield); } static Type *CTemplTool_DeduceTemplDepType(TypeDeduce *deduce, TypeTemplDep *tdt, UInt32 *resultQual) { Type *type; UInt32 qual; TemplArg *arg; qual = 0; if (deduce->x14) { type = CTemplTool_GetSelfRefTemplate(TYPE(tdt)); if (type && type == TYPE(deduce->tmclass)) return type; switch (tdt->dtype) { case TEMPLDEP_ARGUMENT: return TYPE(tdt); case TEMPLDEP_QUALNAME: type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual); if (type == TYPE(tdt->u.qual.type)) return TYPE(tdt); if (!IS_TYPE_CLASS(type)) { TypeTemplDep *tdtCopy; CError_ASSERT(2157, IS_TYPE_TEMPLATE(type)); tdtCopy = galloc(sizeof(TypeTemplDep)); *tdtCopy = *tdt; tdtCopy->u.qual.type = TYPE_TEMPLATE(type); return TYPE(tdtCopy); } else if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) { return type; } else { CError_Error(CErrorStr150, tdt->u.qual.name->name); return TYPE(tdt); } case TEMPLDEP_TEMPLATE: for (arg = tdt->u.templ.args; arg; arg = arg->next) { if (arg->pid.type == TPT_TYPE) arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); } return TYPE(tdt); case TEMPLDEP_ARRAY: tdt->u.array.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.array.type, &qual); return TYPE(tdt); case TEMPLDEP_QUALTEMPL: tdt->u.qualtempl.type = TYPE_TEMPLATE(CTemplTool_DeduceTemplDepType(deduce, tdt->u.qualtempl.type, &qual)); for (arg = tdt->u.qualtempl.args; arg; arg = arg->next) { if (arg->pid.type == TPT_TYPE) arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); } return TYPE(tdt); case TEMPLDEP_BITFIELD: tdt->u.bitfield.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.bitfield.type, &qual); return TYPE(tdt); } } else { switch (tdt->dtype) { case TEMPLDEP_ARGUMENT: if (deduce->x15 && tdt->u.pid.nindex == deduce->nindex) return TYPE(tdt); arg = CTemplTool_DeduceTemplArg(deduce, tdt->u.pid); if (arg->pid.type == TPT_TEMPLATE) { CError_ASSERT(2222, IS_TEMPL_CLASS(arg->data.typeparam.type)); *resultQual = arg->data.typeparam.qual; return arg->data.typeparam.type; } CError_ASSERT(2226, arg->pid.type == TPT_TYPE); *resultQual = arg->data.typeparam.qual; return arg->data.typeparam.type; case TEMPLDEP_QUALNAME: type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual); if (IS_TYPE_CLASS(type)) { CDecl_CompleteType(type); if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) { return type; } else { CError_Error(CErrorStr150, tdt->u.qual.name->name); } } else { if ((deduce->x15 || !deduce->inst) && IS_TYPE_TEMPLATE(type)) { TypeTemplDep *tdtCopy = galloc(sizeof(TypeTemplDep)); *tdtCopy = *tdt; tdtCopy->u.qual.type = TYPE_TEMPLATE(type); return TYPE(tdtCopy); } else { CError_Error(CErrorStr340, tdt->u.qual.name->name); } } return TYPE(&stsignedint); case TEMPLDEP_TEMPLATE: return CTemplTool_DeduceClassInstanceCopy(deduce, tdt->u.templ.templ, tdt->u.templ.args); case TEMPLDEP_ARRAY: return CTemplTool_DeduceArrayCopy(deduce, tdt->u.array.type, tdt->u.array.index, resultQual); case TEMPLDEP_QUALTEMPL: type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qualtempl.type), &qual); if (!IS_TEMPL_CLASS(type)) { CError_Error(CErrorStr121); return TYPE(&stsignedint); } return CTemplTool_DeduceClassInstanceCopy(deduce, TEMPL_CLASS(type), tdt->u.qualtempl.args); case TEMPLDEP_BITFIELD: return CTemplTool_DeduceBitfieldCopy(deduce, tdt->u.bitfield.type, tdt->u.bitfield.size, resultQual); } } CError_FATAL(2275); return NULL; } static Type *CTemplTool_DeduceTypeQualCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) { Type *innerType; UInt32 qual; UInt32 innerQual; TypePointer *newPtr; qual = *resultQual; if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_TEMPLATE(TPTR_TARGET(type))) { innerQual = 0; innerType = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(TPTR_TARGET(type)), &innerQual); newPtr = galloc(sizeof(TypePointer)); *newPtr = *TYPE_POINTER(type); if (IS_TYPE_POINTER_ONLY(innerType)) { newPtr->target = galloc(sizeof(TypePointer)); *TYPE_POINTER(newPtr->target) = *TYPE_POINTER(innerType); *resultQual = innerQual & (Q_CONST | Q_VOLATILE); TPTR_QUAL(newPtr->target) |= qual & (Q_CONST | Q_VOLATILE); } else if (IS_TYPE_MEMBERPOINTER(innerType)) { newPtr->target = galloc(sizeof(TypeMemberPointer)); *TYPE_MEMBER_POINTER(newPtr->target) = *TYPE_MEMBER_POINTER(innerType); *resultQual = innerQual & (Q_CONST | Q_VOLATILE); TYPE_MEMBER_POINTER(newPtr->target)->qual |= qual & (Q_CONST | Q_VOLATILE); } else { newPtr->target = innerType; *resultQual = (qual | innerQual) & (Q_CONST | Q_VOLATILE); } return TYPE(newPtr); } return CTemplTool_DeduceTypeCopy(deduce, type, resultQual); } FuncArg *CTemplTool_DeduceArgCopy(TypeDeduce *deduce, FuncArg *args) { FuncArg *resultArgs; FuncArg *last; if (args == &oldstyle || args == &elipsis) return args; resultArgs = NULL; while (args) { if (args == &elipsis) { last->next = args; break; } if (resultArgs) { last->next = galloc(sizeof(FuncArg)); last = last->next; } else { last = galloc(sizeof(FuncArg)); resultArgs = last; } *last = *args; last->type = CTemplTool_DeduceTypeQualCopy(deduce, last->type, &last->qual); CanCreateObject(last->type); args = args->next; } return resultArgs; } static ExceptSpecList *CTemplTool_DeduceExSpecCopy(TypeDeduce *deduce, ExceptSpecList *exspec) { ExceptSpecList *copy; copy = galloc(sizeof(ExceptSpecList)); *copy = *exspec; if (copy->type && CTemplTool_IsTemplateArgumentDependentType(copy->type)) copy->type = CTemplTool_DeduceTypeCopy(deduce, copy->type, ©->qual); if (copy->next) copy->next = CTemplTool_DeduceExSpecCopy(deduce, copy->next); return copy; } Type *CTemplTool_DeduceTypeCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) { TemplClassInst *inst; Type *deduced; UInt32 qual2; UInt32 qual; switch (type->type) { case TYPETEMPLATE: qual = 0; deduced = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(type), &qual); if (*resultQual & (Q_CONST | Q_VOLATILE)) { if (IS_TYPE_POINTER_ONLY(deduced)) { TypePointer *newPtr = galloc(sizeof(TypePointer)); *newPtr = *TYPE_POINTER(deduced); newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE); *resultQual &= ~(Q_CONST | Q_VOLATILE); deduced = TYPE(newPtr); } else if (IS_TYPE_MEMBERPOINTER(deduced)) { TypeMemberPointer *newPtr = galloc(sizeof(TypeMemberPointer)); *newPtr = *TYPE_MEMBER_POINTER(deduced); newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE); *resultQual &= ~(Q_CONST | Q_VOLATILE); deduced = TYPE(newPtr); } } *resultQual |= qual; return deduced; case TYPEVOID: case TYPEINT: case TYPEFLOAT: case TYPESTRUCT: return type; case TYPEENUM: if ( TYPE_ENUM(type)->nspace->theclass && (TYPE_ENUM(type)->nspace->theclass->flags & CLASS_IS_TEMPL) && !deduce->x14 ) { CError_ASSERT(2471, TYPE_ENUM(type)->enumname); inst = TEMPL_CLASS_INST(CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(TYPE_ENUM(type)->nspace->theclass))); CError_ASSERT(2473, inst && inst->theclass.type == TYPECLASS); CDecl_CompleteType(TYPE(inst)); type = CScope_GetLocalTagType(inst->theclass.nspace, TYPE_ENUM(type)->enumname); CError_ASSERT(2477, type); return type; } return type; case TYPECLASS: if (!deduce->x14) { if (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL) return CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(type)); if (TYPE_CLASS(type)->nspace->theclass && (TYPE_CLASS(type)->nspace->theclass->flags & CLASS_IS_TEMPL)) { CError_ASSERT(2492, deduce->inst); CError_ASSERT(2493, TYPE_CLASS(type)->classname); type = CScope_GetLocalTagType(deduce->inst->theclass.nspace, TYPE_CLASS(type)->classname); CError_ASSERT(2496, type); return type; } } return type; case TYPEARRAY: { SInt32 elements; elements = TPTR_TARGET(type)->size; if (elements > 0) elements = type->size / elements; deduced = galloc(sizeof(TypePointer)); *TYPE_POINTER(deduced) = *TYPE_POINTER(type); TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual); do { type = TPTR_TARGET(type); } while (IS_TYPE_ARRAY(type)); if (IS_TYPE_TEMPLATE(type)) { CDecl_CompleteType(TPTR_TARGET(deduced)); deduced->size = TPTR_TARGET(deduced)->size * elements; } return deduced; } case TYPEPOINTER: deduced = galloc(sizeof(TypePointer)); *TYPE_POINTER(deduced) = *TYPE_POINTER(type); TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual); return deduced; case TYPEBITFIELD: deduced = galloc(sizeof(TypeBitfield)); *TYPE_BITFIELD(deduced) = *TYPE_BITFIELD(type); TYPE_BITFIELD(deduced)->bitfieldtype = CTemplTool_DeduceTypeCopy(deduce, TYPE_BITFIELD(type)->bitfieldtype, resultQual); return deduced; case TYPEMEMBERPOINTER: deduced = galloc(sizeof(TypeMemberPointer)); *TYPE_MEMBER_POINTER(deduced) = *TYPE_MEMBER_POINTER(type); TYPE_MEMBER_POINTER(deduced)->ty1 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty1, resultQual); qual2 = 0; TYPE_MEMBER_POINTER(deduced)->ty2 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty2, &qual2); if ( !IS_TYPE_CLASS(TYPE_MEMBER_POINTER(deduced)->ty2) && !deduce->x14 && !deduce->x15 && !deduce->x16 ) { CError_Error(CErrorStr232); return TYPE_MEMBER_POINTER(deduced)->ty1; } return deduced; case TYPEFUNC: if (TYPE_FUNC(type)->flags & FUNC_METHOD) { qual2 = 0; deduced = galloc(sizeof(TypeMemberFunc)); *TYPE_METHOD(deduced) = *TYPE_METHOD(type); TYPE_METHOD(deduced)->funcid = 0; TYPE_METHOD(deduced)->theclass = TYPE_CLASS(CTemplTool_DeduceTypeQualCopy(deduce, TYPE(TYPE_METHOD(type)->theclass), &qual2)); CError_ASSERT(2556, IS_TYPE_CLASS(TYPE_METHOD(deduced)->theclass)); } else { deduced = galloc(sizeof(TypeFunc)); *TYPE_FUNC(deduced) = *TYPE_FUNC(type); } TYPE_FUNC(deduced)->flags &= ~FUNC_IS_TEMPL; qual2 = TYPE_FUNC(type)->qual; TYPE_FUNC(deduced)->functype = CTemplTool_DeduceTypeQualCopy(deduce, TYPE_FUNC(type)->functype, &qual2); TYPE_FUNC(deduced)->qual = qual2; TYPE_FUNC(deduced)->args = CTemplTool_DeduceArgCopy(deduce, TYPE_FUNC(type)->args); if (TYPE_FUNC(type)->exspecs) TYPE_FUNC(deduced)->exspecs = CTemplTool_DeduceExSpecCopy(deduce, TYPE_FUNC(type)->exspecs); CDecl_SetResultReg(TYPE_FUNC(deduced)); return deduced; case TYPETEMPLDEPEXPR: CError_Error(CErrorStr190); return &stvoid; default: CError_FATAL(2580); return NULL; } } Type *CTemplTool_ResolveMemberSelfRefs(TemplClass *templ, Type *type, UInt32 *resultQual) { TypeDeduce deduce; memclrw(&deduce, sizeof(deduce)); deduce.tmclass = templ; deduce.x14 = 1; if (IS_TYPE_FUNC(type)) { TYPE_FUNC(type)->functype = CTemplTool_DeduceTypeCopy(&deduce, TYPE_FUNC(type)->functype, &TYPE_FUNC(type)->qual); TYPE_FUNC(type)->args = CTemplTool_DeduceArgCopy(&deduce, TYPE_FUNC(type)->args); CDecl_SetResultReg(TYPE_FUNC(type)); } else { type = CTemplTool_DeduceTypeCopy(&deduce, type, resultQual); } return type; } Boolean CTemplTool_IsSameTemplateType(Type *a, Type *b) { return CTemplTool_GetSelfRefTemplate(b) == a; }