MWCC/compiler_and_linker/unsorted/CTemplateTools.c

1963 lines
64 KiB
C
Raw Normal View History

2022-12-29 12:32:55 +00:00
#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_FLAGS_1000) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_FLAGS_20)) {
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_FLAGS_800)) {
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_FLAGS_800) && 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_FLAGS_100) ? 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_FLAGS_2 | CLASS_FLAGS_800)) == CLASS_FLAGS_800)
2023-01-11 22:29:53 +00:00
CTempl_InstantiateTemplateClass(TYPE_CLASS(inst));
2022-12-29 12:32:55 +00:00
}
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_FLAGS_100);
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;
CScopeParseResult 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_FLAGS_METHOD) && (TYPE_METHOD(func->type)->theclass->flags & CLASS_FLAGS_800)) {
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->unkB = 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, &copy->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_FLAGS_100) &&
!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_FLAGS_100)
return CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(type));
if (TYPE_CLASS(type)->nspace->theclass && (TYPE_CLASS(type)->nspace->theclass->flags & CLASS_FLAGS_100)) {
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_FLAGS_METHOD) {
qual2 = 0;
deduced = galloc(sizeof(TypeMethod));
*TYPE_METHOD(deduced) = *TYPE_METHOD(type);
TYPE_METHOD(deduced)->x22 = 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_FLAGS_100000;
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;
}