summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/C/CTemplateClass.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CTemplateClass.c')
-rw-r--r--compiler_and_linker/FrontEnd/C/CTemplateClass.c1632
1 files changed, 1632 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateClass.c b/compiler_and_linker/FrontEnd/C/CTemplateClass.c
new file mode 100644
index 0000000..8b3b889
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CTemplateClass.c
@@ -0,0 +1,1632 @@
+#include "compiler/CTemplateClass.h"
+#include "compiler/CABI.h"
+#include "compiler/CBrowse.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+TemplClass *CTemplClass_GetMasterTemplate(TemplClass *tmclass) {
+ if (tmclass->inst_parent) {
+ tmclass = TEMPL_CLASS(tmclass->theclass.nspace->theclass);
+ CError_ASSERT(42, tmclass->theclass.flags & CLASS_IS_TEMPL);
+ }
+
+ return tmclass;
+}
+
+static void CTemplClass_SetupActionErrorRef(TemplateAction *action, TStreamElement **saved) {
+ CError_ResetErrorSkip();
+ CError_LockErrorPos(&action->source_ref, saved);
+}
+
+static void CTemplClass_RestoreActionErrorRef(TStreamElement **saved) {
+ CError_ResetErrorSkip();
+ CError_UnlockErrorPos(saved);
+}
+
+static void CTemplClass_AppendTemplateAction(TemplClass *tmclass, TemplateAction *action) {
+ TemplateAction *last;
+
+ action->source_ref = *CPrep_CurStreamElement();
+
+ if ((last = tmclass->actions)) {
+ while (last->next)
+ last = last->next;
+ last->next = action;
+ } else {
+ tmclass->actions = action;
+ }
+}
+
+static DefAction *CTemplClass_NewDefAction(TypeDeduce *deduce, TemplateAction *action) {
+ DefAction *defAction = lalloc(sizeof(DefAction));
+ defAction->next = deduce->defActions;
+ defAction->action = action;
+ deduce->defActions = defAction;
+ return defAction;
+}
+
+static void CTemplClass_InsertTemplateAction(TemplClass *tmclass, TemplateAction *action) {
+ action->source_ref = *CPrep_CurStreamElement();
+ action->next = tmclass->actions;
+ tmclass->actions = action;
+}
+
+void CTemplClass_RegisterUsingDecl(TemplClass *tmclass, TypeTemplDep *type, AccessType access) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_USINGDECL;
+ action->u.usingdecl.type = type;
+ action->u.usingdecl.access = access;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterFriend(TemplClass *tmclass, DeclInfo *di) {
+ TemplateFriend *tfriend;
+ TemplateAction *action;
+
+ tfriend = galloc(sizeof(TemplateFriend));
+ memclrw(tfriend, sizeof(TemplateFriend));
+
+ if (tk == '{' && IS_TYPE_FUNC(di->thetype)) {
+ di->qual |= Q_INLINE;
+ TYPE_FUNC(di->thetype)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE;
+ tfriend->fileoffset = cparser_fileoffset;
+
+ CPrep_StreamGetBlock(&tfriend->stream, NULL, 1);
+
+ if (lookahead() == ';')
+ tk = lex();
+ else
+ tk = ';';
+ }
+
+ CDecl_PackDeclInfo(&tfriend->decl, di);
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_FRIEND;
+ action->u.tfriend = tfriend;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterBaseClass(TemplClass *tmclass, Type *type, AccessType access, Boolean is_virtual) {
+ TemplateAction *action;
+ ClassList *insert_after;
+
+ if ((insert_after = tmclass->theclass.bases)) {
+ while (insert_after->next)
+ insert_after = insert_after->next;
+ }
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_BASE;
+ action->u.base.type = type;
+ action->u.base.insert_after = insert_after;
+ action->u.base.access = access;
+ action->u.base.is_virtual = is_virtual;
+
+ CTemplClass_InsertTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterEnumType(TemplClass *tmclass, TypeEnum *enumtype) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_ENUMTYPE;
+ action->u.enumtype = enumtype;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterEnumerator(TemplClass *tmclass, ObjEnumConst *objenumconst, ENode *initexpr) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_ENUMERATOR;
+ action->u.enumerator.objenumconst = objenumconst;
+ action->u.enumerator.initexpr = initexpr ? CInline_CopyExpression(initexpr, CopyMode1) : NULL;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterObjectInit(TemplClass *tmclass, Object *object, ENode *initexpr) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_OBJECTINIT;
+ action->u.objectinit.object = object;
+ action->u.objectinit.initexpr = CInline_CopyExpression(initexpr, CopyMode1);
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterObjectDef(TemplClass *tmclass, ObjBase *refobj) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_OBJECTDEF;
+ action->u.refobj = refobj;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_CompleteClass(TemplClass *templ, ClassLayout *de) {
+ templ->lex_order_count = de->lex_order_count;
+ if (de->has_vtable)
+ templ->flags |= TEMPLCLASS_HAS_VTABLE;
+ templ->theclass.flags |= CLASS_COMPLETED;
+}
+
+static TemplClassInst *CTemplClass_NewInstance(TemplClass *templ, TemplArg *inst_args, TemplArg *oargs) {
+ TemplClassInst *inst;
+ ObjTypeTag *tag;
+ NameSpace *nspace;
+ HashNameNode *name;
+
+ CError_ASSERT(288, !templ->pspec_owner);
+
+ inst = galloc(sizeof(TemplClassInst));
+ memclrw(inst, sizeof(TemplClassInst));
+
+ inst->next = templ->instances;
+ templ->instances = inst;
+
+ if (templ->templ__params)
+ name = CMangler_TemplateInstanceName(templ->theclass.classname, oargs ? oargs : inst_args);
+ else
+ name = templ->theclass.classname;
+
+ inst->inst_args = inst_args;
+ inst->oargs = oargs;
+ inst->parent = templ->inst_parent;
+
+ nspace = CScope_NewListNameSpace(name, 1);
+ nspace->theclass = TYPE_CLASS(inst);
+ if (templ->templ_parent && templ->inst_parent) {
+ nspace->parent = TYPE_CLASS(templ->inst_parent)->nspace;
+ } else {
+ NameSpace *scan = templ->theclass.nspace->parent;
+ while (scan->is_templ)
+ scan = scan->parent;
+ nspace->parent = scan;
+ }
+
+ inst->theclass.type = TYPECLASS;
+ inst->theclass.flags = CLASS_IS_TEMPL_INST;
+ inst->theclass.nspace = nspace;
+ inst->theclass.classname = templ->theclass.classname;
+ inst->theclass.mode = templ->theclass.mode;
+ inst->theclass.eflags = templ->theclass.eflags;
+ inst->templ = templ;
+
+ tag = galloc(sizeof(ObjTypeTag));
+ memclrw(tag, sizeof(ObjTypeTag));
+
+ tag->otype = OT_TYPETAG;
+ tag->access = ACCESSPUBLIC;
+ tag->type = TYPE(inst);
+ CScope_AddObject(nspace, templ->theclass.classname, OBJ_BASE(tag));
+
+ return inst;
+}
+
+TemplClassInst *CTemplClass_GetInstance(TemplClass *tmclass, TemplArg *inst_args, TemplArg *oargs) {
+ TemplClassInst *inst;
+
+ for (inst = tmclass->instances; inst; inst = inst->next) {
+ CError_ASSERT(353, !oargs);
+
+ if (CTemplTool_EqualArgs(inst_args, inst->oargs ? inst->oargs : inst->inst_args))
+ return inst;
+ }
+
+ return CTemplClass_NewInstance(tmclass, inst_args, oargs);
+}
+
+TemplateMember *CTemplClass_DefineMember(TemplClass *tmclass, Object *object, FileOffsetInfo *foi, TokenStream *stream) {
+ TemplateMember *member;
+
+ for (member = tmclass->members; member; member = member->next) {
+ if (member->object == object) {
+ CError_Error(CErrorStr333, object);
+ return member;
+ }
+ }
+
+ member = galloc(sizeof(TemplateMember));
+ memclrw(member, sizeof(TemplateMember));
+ member->next = tmclass->members;
+ tmclass->members = member;
+
+ member->params = NULL;
+ member->object = object;
+ member->fileoffset = *foi;
+ member->stream = *stream;
+
+ return member;
+}
+
+static void CTemplClass_ParseBody(TemplClass *templ, short mode, SInt32 *offset) {
+ DeclInfo di;
+
+ templ->align = copts.structalignment;
+
+ memclrw(&di, sizeof(di));
+ di.file = CPrep_BrowserCurrentFile();
+ CPrep_BrowserFilePosition(&di.file2, &di.sourceoffset);
+ di.sourceoffset = *offset;
+ di.x28 = templ;
+
+ CDecl_ParseClass(&di, mode, 1, 0);
+
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di.thetype, NULL);
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+
+ CBrowse_NewTemplateClass(templ, di.file2, di.sourceoffset, CPrep_BrowserFileOffset() + 1);
+}
+
+void CTemplClass_ParsePartialSpecialization(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) {
+ Type *type;
+ NameSpace *nspace;
+ TemplArg *args;
+ TemplPartialSpec *pspec;
+ TemplClass *templ;
+ TemplArg *arg;
+ TemplParam *param;
+
+ nspace = what_is_this->nspace;
+
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return;
+ }
+
+ if (!(type = CScope_GetLocalTagType(nspace, tkidentifier))) {
+ CError_Error(CErrorStr140, tkidentifier->name);
+ return;
+ }
+
+ if (!IS_TEMPL_CLASS(type)) {
+ CError_Error(CErrorStr132, tkidentifier->name);
+ return;
+ }
+
+ if ((tk = lex()) != '<')
+ CError_FATAL(469);
+
+ for (param = params; param; param = param->next) {
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ if (!param->data.typeparam.type)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ case TPT_NONTYPE:
+ if (!param->data.paramdecl.defaultarg)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ case TPT_TEMPLATE:
+ if (!param->data.templparam.defaultarg)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ default:
+ CError_FATAL(501);
+ }
+
+ break;
+ }
+
+ args = CTempl_ParseUncheckTemplArgs(TEMPL_CLASS(type)->templ__params, 0);
+ tk = lex();
+
+ arg = args;
+ param = TEMPL_CLASS(type)->templ__params;
+ while (1) {
+ if (!arg) {
+ if (!param)
+ break;
+ CError_Error(CErrorStr344);
+ return;
+ }
+ if (!param) {
+ CError_Error(CErrorStr344);
+ return;
+ }
+ if (param->pid.type != arg->pid.type) {
+ CError_Error(CErrorStr344);
+ return;
+ }
+ arg = arg->next;
+ param = param->next;
+ }
+
+ if (CTemplTool_IsSameTemplate(TEMPL_CLASS(type)->templ__params, args))
+ CError_Error(CErrorStr344);
+
+ for (pspec = TEMPL_CLASS(type)->pspecs; pspec; pspec = pspec->next) {
+ if (CTemplTool_EqualParams(pspec->templ->templ__params, params, 0) && CTemplTool_EqualArgs(pspec->args, args))
+ break;
+ }
+
+ if (!pspec) {
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->templ__params = params;
+ CDecl_DefineClass(nspace, TEMPL_CLASS(type)->theclass.classname, TYPE_CLASS(templ), mode, 0, 0);
+
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->pspec_owner = TEMPL_CLASS(type);
+
+ pspec = galloc(sizeof(TemplPartialSpec));
+ memclrw(pspec, sizeof(TemplPartialSpec));
+
+ pspec->templ = templ;
+ pspec->args = CTemplTool_MakeGlobalTemplArgCopy(args);
+ pspec->next = TEMPL_CLASS(type)->pspecs;
+ TEMPL_CLASS(type)->pspecs = pspec;
+ } else {
+ if ((pspec->templ->theclass.flags & CLASS_COMPLETED) && tk != ';') {
+ CError_Error(CErrorStr132, TEMPL_CLASS(type)->theclass.classname->name);
+ return;
+ }
+
+ if (tk == ':' || tk == '{')
+ CTemplTool_EqualParams(pspec->templ->templ__params, params, 1);
+ }
+
+ switch (tk) {
+ case ':':
+ case '{':
+ CTemplClass_ParseBody(pspec->templ, mode, offset);
+ break;
+ case ';':
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ }
+}
+
+void CTemplClass_ParseClass(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) {
+ TemplClass *templ;
+ NameSpace *nspace;
+ Type *type;
+ UInt8 classDeclSpec = 0;
+
+ nspace = what_is_this->nspace;
+ if ((tk = lex()) == TK_UU_DECLSPEC)
+ CDecl_ParseClassDeclSpec(&classDeclSpec);
+
+ if (tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return;
+ }
+
+ type = CScope_GetLocalTagType(nspace, tkidentifier);
+ if (!type) {
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->next = ctempl_templates;
+ ctempl_templates = templ;
+
+ templ->templ__params = params;
+ CDecl_DefineClass(nspace, tkidentifier, TYPE_CLASS(templ), mode, 0, 1);
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->theclass.eflags = classDeclSpec;
+
+ tk = lex();
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ TemplateAction *action;
+
+ templ->templ_parent = TEMPL_CLASS(nspace->theclass);
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_NESTEDCLASS;
+ action->u.tclasstype = templ;
+ CTemplClass_AppendTemplateAction(templ->templ_parent, action);
+ }
+ } else {
+ if (!IS_TEMPL_CLASS(type)) {
+ CError_Error(CErrorStr132, tkidentifier->name);
+ return;
+ }
+
+ templ = TEMPL_CLASS(type);
+ if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) {
+ CError_Error(CErrorStr132, templ->theclass.classname->name);
+ return;
+ }
+
+ CTemplTool_MergeDefaultArgs(templ->templ__params, params);
+ templ->theclass.eflags |= classDeclSpec;
+
+ tk = lex();
+
+ if ((templ->theclass.flags & CLASS_COMPLETED) && tk != ';') {
+ CError_Error(CErrorStr132, templ->theclass.classname->name);
+ return;
+ }
+
+ if (tk != ';')
+ CTemplTool_EqualParams(templ->templ__params, params, 1);
+ }
+
+ switch (tk) {
+ case ':':
+ case '{':
+ CTemplClass_ParseBody(templ, mode, offset);
+ break;
+ case ';':
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ }
+}
+
+static Boolean CTemplClass_TypeParamCompare(TemplArg *arg, Type *type, UInt32 qual) {
+ return is_typesame(type, arg->data.typeparam.type) && arg->data.typeparam.qual == qual;
+}
+
+static TemplArg *CTemplClass_PartialTemplateArgMatch(TemplPartialSpec *pspec, TemplArg *args, Boolean flag) {
+ TemplArg *argA;
+ TemplArg *argB;
+ int i;
+ DeduceInfo info;
+
+ if (!CTemplTool_InitDeduceInfo(&info, pspec->templ->templ__params, NULL, 1))
+ return NULL;
+
+ argA = pspec->args;
+ argB = args;
+ while (1) {
+ if (!argA) {
+ if (argB)
+ return NULL;
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return NULL;
+ }
+
+ if (flag)
+ return CTemplTool_MakeTemplArgList(&info);
+ else
+ return args;
+ }
+
+ if (!argB)
+ return NULL;
+
+ if (argA->pid.type != argB->pid.type)
+ return NULL;
+
+ switch (argA->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(argA->data.typeparam.type)) {
+ if (!CTempl_DeduceType(
+ argA->data.typeparam.type, argA->data.typeparam.qual,
+ argB->data.typeparam.type, argB->data.typeparam.qual,
+ info.args, 0, 0
+ ))
+ return NULL;
+ } else {
+ if (
+ !is_typesame(argA->data.typeparam.type, argB->data.typeparam.type) ||
+ argA->data.typeparam.qual != argB->data.typeparam.qual
+ )
+ return NULL;
+ }
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(argA->data.paramdecl.expr)) {
+ i = CTempl_GetTemplateArgumentExpressionIndex(argA);
+ CError_ASSERT(789, i >= 0);
+
+ if (info.args[i].is_deduced) {
+ if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, info.args[i].data.paramdecl.expr))
+ return NULL;
+ } else {
+ info.args[i].data.paramdecl.expr = argB->data.paramdecl.expr;
+ info.args[i].pid.type = TPT_NONTYPE;
+ info.args[i].is_deduced = 1;
+ }
+ } else {
+ if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, argA->data.paramdecl.expr))
+ return NULL;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (CTemplTool_IsTemplateArgumentDependentType(argA->data.ttargtype)) {
+ if (!CTempl_DeduceType(
+ argA->data.ttargtype, 0,
+ argB->data.ttargtype, 0,
+ info.args, 0, 0
+ ))
+ return NULL;
+ } else {
+ if (!is_typesame(argA->data.ttargtype, argB->data.ttargtype))
+ return NULL;
+ }
+ break;
+
+ default:
+ CError_FATAL(830);
+ }
+
+ argA = argA->next;
+ argB = argB->next;
+ }
+}
+
+static Boolean CTemplClass_PartialClassIsAtLeastAsSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) {
+ TemplArg *argA;
+ TemplArg *argB;
+ int i;
+ DeduceInfo info;
+
+ if (!CTemplTool_InitDeduceInfo(&info, pspec2->templ->templ__params, NULL, 1))
+ return 0;
+
+ argA = pspec1->args;
+ argB = pspec2->args;
+
+ while (1) {
+ if (!argA) {
+ CError_ASSERT(856, !argB);
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return 0;
+ }
+
+ return 1;
+ }
+
+ CError_ASSERT(865, argB);
+ CError_ASSERT(866, argA->pid.type == argB->pid.type);
+
+ switch (argA->pid.type) {
+ case TPT_TYPE:
+ if (!CTempl_DeduceType(
+ argB->data.typeparam.type, argB->data.typeparam.qual,
+ argA->data.typeparam.type, argA->data.typeparam.qual,
+ info.args, 0, 0
+ ))
+ return 0;
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(argB->data.paramdecl.expr)) {
+ i = CTempl_GetTemplateArgumentExpressionIndex(argB);
+ CError_ASSERT(907, i >= 0);
+
+ if (info.args[i].is_deduced) {
+ if (argA->data.paramdecl.expr) {
+ if (!info.args[i].data.paramdecl.expr || !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, info.args[i].data.paramdecl.expr))
+ return 0;
+ } else {
+ if (info.args[i].data.paramdecl.expr || argA->pid.index != info.args[i].pid.index)
+ return 0;
+ }
+ } else {
+ info.args[i].data.paramdecl.expr = argA->data.paramdecl.expr;
+ info.args[i].pid.index = argA->pid.index;
+ info.args[i].pid.type = TPT_NONTYPE;
+ info.args[i].is_deduced = 1;
+ }
+ } else {
+ if (
+ !argA->data.paramdecl.expr ||
+ !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, argB->data.paramdecl.expr)
+ )
+ return 0;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (!CTempl_DeduceType(
+ argB->data.ttargtype, 0,
+ argA->data.ttargtype, 0,
+ info.args, 0, 0
+ ))
+ return 0;
+ break;
+
+ default:
+ CError_FATAL(955);
+ }
+
+ argA = argA->next;
+ argB = argB->next;
+ }
+}
+
+static Boolean CTemplClass_PartialClassIsMoreSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) {
+ return CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec1, pspec2) &&
+ !CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec2, pspec1);
+}
+
+typedef struct PSpecList {
+ struct PSpecList *next;
+ TemplPartialSpec *pspec;
+} PSpecList;
+
+static PSpecList *CTemplClass_FindMostSpecializedPartialSpecializations(PSpecList *list) {
+ PSpecList **array;
+ PSpecList *scan;
+ int i;
+ int j;
+ int count;
+
+ scan = list;
+ count = 0;
+ while (scan) {
+ scan = scan->next;
+ count++;
+ }
+
+ array = lalloc(sizeof(PSpecList *) * count);
+ for (i = 0, scan = list; scan; scan = scan->next)
+ array[i++] = scan;
+
+ for (i = 0; i < count; i++) {
+ if (array[i]) {
+ for (j = 0; j < count; j++) {
+ if (array[j] && i != j && CTemplClass_PartialClassIsMoreSpecialized(array[i]->pspec, array[j]->pspec))
+ array[j] = NULL;
+ }
+ }
+ }
+
+ for (i = 0, list = NULL; i < count; i++) {
+ if (array[i]) {
+ if (!list)
+ list = array[i];
+ else
+ array[j]->next = array[i];
+ array[i]->next = NULL;
+ j = i;
+ }
+ }
+
+ return list;
+}
+
+Boolean CTemplClass_FindPartialTemplate(TemplArg *args, TemplClass **resultTempl, TemplArg **resultArgs) {
+ TemplPartialSpec *pspec;
+ PSpecList *list;
+ TemplClassInst *inst;
+
+ for (inst = (*resultTempl)->instances; inst; inst = inst->next) {
+ if (inst->is_instantiated || inst->is_specialized) {
+ if (CTemplTool_EqualArgs(args, inst->oargs ? inst->oargs : inst->inst_args))
+ return 0;
+ }
+ }
+
+ list = NULL;
+ for (pspec = (*resultTempl)->pspecs; pspec; pspec = pspec->next) {
+ if (CTemplClass_PartialTemplateArgMatch(pspec, args, 0)) {
+ PSpecList *entry = lalloc(sizeof(PSpecList));
+ entry->next = list;
+ entry->pspec = pspec;
+ list = entry;
+ }
+ }
+
+ if (list) {
+ if (list->next) {
+ list = CTemplClass_FindMostSpecializedPartialSpecializations(list);
+ if (list->next)
+ CError_Error(CErrorStr346);
+ }
+
+ if (!list->pspec->templ->templ__params) {
+ *resultTempl = list->pspec->templ;
+ *resultArgs = NULL;
+ return 1;
+ }
+
+ *resultTempl = list->pspec->templ;
+ *resultArgs = CTemplClass_PartialTemplateArgMatch(list->pspec, args, 1);
+ return *resultArgs != NULL;
+ } else {
+ return 0;
+ }
+}
+
+TemplClass *CTemplClass_DefineNestedClass(TemplClass *parent, HashNameNode *name, short mode) {
+ TemplateAction *action;
+ TemplClass *templ;
+
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->next = ctempl_templates;
+ ctempl_templates = templ;
+
+ templ->templ_parent = parent;
+ templ->templ__params = NULL;
+ CDecl_DefineClass(parent->theclass.nspace, name, TYPE_CLASS(templ), mode, 0, 1);
+
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->align = copts.structalignment;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_NESTEDCLASS;
+ action->u.tclasstype = templ;
+ CTemplClass_AppendTemplateAction(parent, action);
+
+ return templ;
+}
+
+static void CTemplClass_CopyNestedClass(TypeDeduce *deduce, TemplClass *templ) {
+ ObjTypeTag *tag;
+
+ tag = galloc(sizeof(ObjTypeTag));
+ memclrw(tag, sizeof(ObjTypeTag));
+
+ tag->otype = OT_TYPETAG;
+ tag->access = ACCESSPUBLIC;
+
+ if (!templ->templ__params) {
+ TemplClassInst *inst = CTemplClass_NewInstance(templ, NULL, NULL);
+ inst->parent = deduce->inst;
+ inst->theclass.nspace->parent = deduce->inst->theclass.nspace;
+
+ tag->type = TYPE(inst);
+ } else {
+ TemplClass *copy = galloc(sizeof(TemplClass));
+ memclrw(copy, sizeof(TemplClass));
+
+ copy->next = ctempl_templates;
+ ctempl_templates = copy;
+
+ copy->theclass = templ->theclass;
+ copy->templ_parent = deduce->tmclass;
+ copy->inst_parent = deduce->inst;
+ copy->templ__params = templ->templ__params;
+ copy->members = NULL;
+ copy->instances = NULL;
+ copy->pspecs = NULL;
+ copy->actions = templ->actions;
+ copy->lex_order_count = templ->lex_order_count;
+ copy->align = templ->align;
+ copy->flags = templ->flags;
+
+ tag->type = TYPE(copy);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, templ->theclass.classname, OBJ_BASE(tag));
+}
+
+static void CTemplClass_CopyBaseClasses(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ TemplateAction *action;
+ ClassList *newBase;
+ ClassList *templbase;
+ ClassList *instbase;
+ ClassList *base;
+ UInt32 qual = 0;
+
+ for (base = templ->theclass.bases; base; base = base->next) {
+ ClassList *scan;
+ newBase = galloc(sizeof(ClassList));
+ *newBase = *base;
+ newBase->next = NULL;
+
+ if ((scan = inst->theclass.bases)) {
+ while (1) {
+ if (scan->base == newBase->base) {
+ CError_Error(CErrorStr131);
+ break;
+ }
+ if (!scan->next) {
+ scan->next = newBase;
+ break;
+ }
+ scan = scan->next;
+ }
+ } else {
+ inst->theclass.bases = newBase;
+ }
+ }
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_BASE) {
+ TStreamElement *save;
+
+ CTemplClass_SetupActionErrorRef(action, &save);
+
+ newBase = galloc(sizeof(ClassList));
+ memclrw(newBase, sizeof(ClassList));
+
+ newBase->base = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, action->u.base.type, &qual));
+ newBase->access = action->u.base.access;
+ newBase->is_virtual = action->u.base.is_virtual;
+
+ if (IS_TYPE_CLASS(newBase->base)) {
+ if (newBase->base->size == 0) {
+ CDecl_CompleteType(TYPE(newBase->base));
+ IsCompleteType(TYPE(newBase->base));
+ }
+
+ if (CDecl_CheckNewBase(TYPE_CLASS(inst), newBase->base, newBase->is_virtual)) {
+ if (action->u.base.insert_after) {
+ templbase = templ->theclass.bases;
+ instbase = inst->theclass.bases;
+ while (1) {
+ CError_ASSERT(1222, templbase && instbase);
+
+ if (templbase == action->u.base.insert_after) {
+ newBase->next = instbase->next;
+ instbase->next = newBase;
+ break;
+ }
+
+ templbase = templbase->next;
+ instbase = instbase->next;
+ }
+ } else {
+ newBase->next = inst->theclass.bases;
+ inst->theclass.bases = newBase;
+ }
+ }
+ } else {
+ CError_Error(CErrorStr131);
+ }
+
+ CTemplClass_RestoreActionErrorRef(&save);
+ }
+ }
+
+ if (inst->theclass.flags & CLASS_HAS_VBASES)
+ CDecl_MakeVBaseList(TYPE_CLASS(inst));
+}
+
+static void CTemplClass_CopyEnum(TypeDeduce *deduce, TemplateAction *action) {
+ TypeEnum *destenum;
+ TypeEnum *srcenum;
+ ObjEnumConst **destptr;
+ ObjEnumConst *src;
+ TemplateAction *scanaction;
+
+ srcenum = action->u.enumtype;
+ destenum = galloc(sizeof(TypeEnum));
+ memclrw(destenum, sizeof(TypeEnum));
+
+ destenum->type = TYPEENUM;
+ destenum->size = srcenum->size;
+ destenum->nspace = deduce->inst->theclass.nspace;
+ destenum->enumtype = srcenum->enumtype;
+ destenum->enumname = srcenum->enumname;
+
+ if (destenum->enumname)
+ CScope_DefineTypeTag(destenum->nspace, destenum->enumname, TYPE(destenum));
+
+ src = srcenum->enumlist;
+ destptr = &destenum->enumlist;
+ while (src) {
+ ObjEnumConst *dest;
+
+ dest = galloc(sizeof(ObjEnumConst));
+ *dest = *src;
+
+ *destptr = dest;
+ dest->next = NULL;
+ dest->type = TYPE(destenum);
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+
+ src = src->next;
+ destptr = &(*destptr)->next;
+ }
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_ENUMERATOR && scanaction->u.enumerator.objenumconst->type == TYPE(srcenum)) {
+ CTemplClass_NewDefAction(deduce, action)->enumtype = destenum;
+ return;
+ }
+ }
+}
+
+static void CTemplClass_CompleteEnumType(TypeDeduce *deduce, TemplateAction *action, TypeEnum *destenum) {
+ TypeEnum *srcenum;
+ ObjEnumConst *dest;
+ TemplateAction *scanaction;
+ ENode *expr;
+ ObjEnumConst *src;
+
+ srcenum = action->u.enumtype;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_ENUMERATOR) {
+ src = scanaction->u.enumerator.objenumconst;
+ if (src->type == TYPE(srcenum)) {
+ TStreamElement *save;
+
+ CTemplClass_SetupActionErrorRef(scanaction, &save);
+
+ dest = destenum->enumlist;
+ while (dest) {
+ if (dest->name == src->name)
+ break;
+ dest = dest->next;
+ }
+
+ CError_ASSERT(1332, dest);
+
+ if (scanaction->u.enumerator.initexpr) {
+ expr = CTemplTool_DeduceExpr(deduce, scanaction->u.enumerator.initexpr);
+ if (!ENODE_IS(expr, EINTCONST)) {
+ CError_Error(CErrorStr124);
+ CTemplClass_RestoreActionErrorRef(&save);
+ break;
+ }
+ } else {
+ CError_ASSERT(1347, expr);
+ expr->data.intval = CInt64_Add(expr->data.intval, cint64_one);
+ }
+
+ dest->val = expr->data.intval;
+ dest->type = expr->rtype;
+ CTemplClass_RestoreActionErrorRef(&save);
+ }
+ }
+ }
+
+ CDecl_ComputeUnderlyingEnumType(destenum);
+}
+
+static void CTemplClass_CopyObjMemberVarPath(TypeDeduce *deduce, ObjMemberVarPath *ivar) {
+ ObjMemberVarPath *copy;
+
+ copy = galloc(sizeof(ObjMemberVarPath));
+ *copy = *ivar;
+
+ if (copy->path && copy->path->type == TYPE(deduce->tmclass)) {
+ copy->path = CClass_GetPathCopy(copy->path, 1);
+ copy->path->type = TYPE(deduce->inst);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, copy->name, OBJ_BASE(copy));
+}
+
+static void CTemplClass_CopyIVars(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ ObjMemberVar *src;
+ ObjMemberVar *dest;
+ ObjMemberVar **destptr;
+ TemplateAction *scanaction;
+
+ src = templ->theclass.ivars;
+ destptr = &inst->theclass.ivars;
+
+ while (src) {
+ CError_ASSERT(1397, !src->has_path);
+
+ dest = galloc(sizeof(ObjMemberVar));
+ *dest = *src;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src)) {
+ CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest);
+ break;
+ }
+ }
+
+ if (!scanaction) {
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ if (dest->type->size == 0) {
+ CDecl_CompleteType(dest->type);
+ IsCompleteType(dest->type);
+ }
+ }
+
+ if (dest->name && dest->name != no_name_node)
+ CScope_AddObject(inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+
+ *destptr = dest;
+ destptr = &dest->next;
+ src = src->next;
+ }
+}
+
+static void CTemplClass_CopyObjType(TypeDeduce *deduce, ObjType *src, HashNameNode *name) {
+ TemplateAction *scanaction;
+ NameSpaceObjectList *list;
+ NameSpaceObjectList *newlist;
+ ObjType *dest;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ dest = galloc(sizeof(ObjType));
+ *dest = *src;
+
+ if (scanaction)
+ CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest);
+ else
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+
+ if ((list = CScope_FindName(deduce->inst->theclass.nspace, name)) && list->object->otype == OT_TYPETAG) {
+ CError_ASSERT(1470, list->next == NULL);
+
+ newlist = galloc(sizeof(NameSpaceObjectList));
+ newlist->object = list->object;
+ newlist->next = NULL;
+
+ list->object = OBJ_BASE(dest);
+ list->next = newlist;
+ } else {
+ CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest));
+ }
+}
+
+static void CTemplClass_CopyObjTypeTag(TypeDeduce *deduce, ObjTypeTag *src, HashNameNode *name) {
+ UInt32 qual = 0;
+ ObjTypeTag *dest = galloc(sizeof(ObjTypeTag));
+
+ *dest = *src;
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &qual);
+
+ CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CopyMemberTemplate(TypeDeduce *deduce, Object *src) {
+ TemplateFunction *desttempl;
+ Object *dest;
+ TemplateFunction *srctempl;
+ TemplateAction *action;
+
+ srctempl = src->u.func.u.templ;
+ CError_ASSERT(1516, srctempl && srctempl->params);
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ desttempl = galloc(sizeof(TemplateFunction));
+ *desttempl = *srctempl;
+
+ desttempl->next = ctempl_templatefuncs;
+ ctempl_templatefuncs = desttempl;
+
+ desttempl->unk4 = srctempl;
+
+ dest = galloc(sizeof(Object));
+ *dest = *src;
+
+ dest->u.func.u.templ = desttempl;
+ dest->nspace = deduce->inst->theclass.nspace;
+
+ CError_ASSERT(1541, !deduce->x15);
+ deduce->x15 = 1;
+ deduce->nindex = srctempl->params->pid.nindex;
+
+ if (action)
+ CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest);
+ else
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+
+ deduce->x15 = 0;
+
+ CError_ASSERT(1553, IS_TYPE_FUNC(dest->type));
+
+ TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL;
+
+ if (
+ (TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) &&
+ deduce->x17 &&
+ !action
+ )
+ {
+ FuncArg *arg;
+ CError_ASSERT(1560, TYPE_FUNC(dest->type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->type)->args->next;
+ TYPE_FUNC(dest->type)->args->next = arg;
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CopyObject(TypeDeduce *deduce, Object *src) {
+ ObjectTemplated *dest;
+ TemplateAction *action;
+ TemplateAction *action2;
+ Boolean flag;
+
+ flag = 1;
+ if (src->nspace != deduce->tmclass->theclass.nspace) {
+ CError_ASSERT(1587, src->datatype == DALIAS);
+ flag = 0;
+ }
+
+ if (IS_TEMPL_FUNC(src->type)) {
+ CTemplClass_CopyMemberTemplate(deduce, src);
+ return;
+ }
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ dest = galloc(sizeof(ObjectTemplated));
+ dest->object = *src;
+
+ if (action)
+ CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest);
+ else
+ dest->object.type = CTemplTool_DeduceTypeCopy(deduce, dest->object.type, &dest->object.qual);
+
+ if (flag)
+ dest->object.nspace = deduce->inst->theclass.nspace;
+
+ dest->object.qual |= Q_IS_TEMPLATED;
+ dest->parent = src;
+
+ if (IS_TYPE_FUNC(dest->object.type))
+ TYPE_FUNC(dest->object.type)->flags &= ~FUNC_DEFINED;
+
+ switch (dest->object.datatype) {
+ case DDATA:
+ dest->object.u.data.linkname = NULL;
+ for (action2 = deduce->tmclass->actions; action2; action2 = action2->next) {
+ if (action2->type == TAT_OBJECTINIT && action2->u.objectinit.object == src) {
+ CTemplClass_NewDefAction(deduce, action2)->refobj = OBJ_BASE(dest);
+ break;
+ }
+ }
+ break;
+
+ case DABSOLUTE:
+ break;
+
+ case DFUNC:
+ case DVFUNC:
+ dest->object.u.func.linkname = NULL;
+ CError_ASSERT(1650, IS_TYPE_FUNC(dest->object.type));
+ CError_ASSERT(1651, !dest->object.u.func.u.templ && !dest->object.u.func.defargdata);
+
+ if (
+ (TYPE_FUNC(dest->object.type)->flags & FUNC_IS_CTOR) &&
+ deduce->x17 &&
+ !action
+ )
+ {
+ FuncArg *arg;
+ CError_ASSERT(1657, TYPE_FUNC(dest->object.type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->object.type)->args->next;
+ TYPE_FUNC(dest->object.type)->args->next = arg;
+ }
+
+ if (TYPE_FUNC(dest->object.type)->flags & FUNC_CONVERSION) {
+ CError_ASSERT(1665, IS_TYPE_FUNC(src->type));
+ if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) {
+ CError_ASSERT(1668, action);
+ return;
+ }
+ }
+
+ break;
+
+ case DINLINEFUNC:
+ break;
+
+ case DALIAS:
+ if (dest->object.u.alias.member && dest->object.u.alias.member->type == TYPE(deduce->tmclass)) {
+ dest->object.u.alias.member = CClass_GetPathCopy(dest->object.u.alias.member, 1);
+ dest->object.u.alias.member->type = TYPE(deduce->inst);
+ }
+ break;
+
+ case DLOCAL:
+ case DEXPR:
+ CError_FATAL(1688);
+
+ default:
+ CError_FATAL(1691);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->object.name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CompleteObject(TypeDeduce *deduce, TemplateAction *action, ObjBase *refobj) {
+ if (refobj->otype == OT_MEMBERVAR) {
+ ObjMemberVar *ivar = OBJ_MEMBER_VAR(refobj);
+ ivar->type = CTemplTool_DeduceTypeCopy(deduce, ivar->type, &ivar->qual);
+
+ if (ivar->type->size == 0) {
+ CDecl_CompleteType(ivar->type);
+ if (copts.experimental) {
+ if (ivar->next || ivar->type->size != 0 || !IS_TYPE_ARRAY(ivar->type))
+ IsCompleteType(ivar->type);
+ } else {
+ IsCompleteType(ivar->type);
+ }
+ }
+ } else if (refobj->otype == OT_TYPE) {
+ ObjType *obj = OBJ_TYPE(refobj);
+ obj->type = CTemplTool_DeduceTypeCopy(deduce, obj->type, &obj->qual);
+ } else {
+ Object *dest;
+ Object *src;
+
+ CError_ASSERT(1737, refobj->otype == OT_OBJECT);
+
+ dest = OBJECT(refobj);
+ src = OBJECT(action->u.refobj);
+
+ if (IS_TEMPL_FUNC(src->type)) {
+ TemplateFunction *templ = src->u.func.u.templ;
+ CError_ASSERT(1747, templ);
+ CError_ASSERT(1748, !deduce->x15);
+
+ deduce->x15 = 1;
+ deduce->nindex = templ->params->pid.nindex;
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ deduce->x15 = 0;
+
+ CError_ASSERT(1753, IS_TYPE_FUNC(dest->type));
+ TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL;
+ } else {
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ dest->qual |= Q_IS_TEMPLATED;
+
+ if (IS_TYPE_FUNC(dest->type))
+ TYPE_FUNC(dest->type)->flags &= ~FUNC_DEFINED;
+
+ switch (dest->datatype) {
+ case DFUNC:
+ case DVFUNC:
+ CError_ASSERT(1769, IS_TYPE_FUNC(dest->type));
+ if (TYPE_FUNC(dest->type)->flags & FUNC_CONVERSION) {
+ CError_ASSERT(1772, IS_TYPE_FUNC(dest->type));
+ if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) {
+ dest->name = CMangler_ConversionFuncName(
+ TYPE_FUNC(dest->type)->functype, TYPE_FUNC(dest->type)->qual);
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+ }
+ }
+
+ if ((TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) && deduce->x17) {
+ FuncArg *arg;
+ CError_ASSERT(1786, TYPE_FUNC(dest->type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->type)->args->next;
+ TYPE_FUNC(dest->type)->args->next = arg;
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+static void CTemplClass_CompleteObjectInit(TypeDeduce *deduce, TemplateAction *action, Object *object) {
+ ENode *expr = CTemplTool_DeduceExpr(deduce, action->u.objectinit.initexpr);
+
+ if (ENODE_IS(expr, EINTCONST) && (object->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(object->type)) {
+ object->u.data.u.intconst = expr->data.intval;
+ object->qual |= Q_INLINE_DATA | Q_20000;
+ } else {
+ CError_Error(CErrorStr354, object->name->name);
+ }
+}
+
+static void CTemplClass_CopyNameSpace(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ NameSpaceName *nsname;
+ NameSpaceObjectList *list;
+
+ CError_ASSERT(1830, !templ->theclass.nspace->is_hash);
+
+ for (nsname = templ->theclass.nspace->data.list; nsname; nsname = nsname->next) {
+ for (list = &nsname->first; list; list = list->next) {
+ switch (list->object->otype) {
+ case OT_ENUMCONST:
+ break;
+ case OT_MEMBERVAR:
+ if (OBJ_MEMBER_VAR(list->object)->has_path)
+ CTemplClass_CopyObjMemberVarPath(deduce, OBJ_MEMBER_VAR_PATH(list->object));
+ break;
+ case OT_TYPE:
+ CTemplClass_CopyObjType(deduce, OBJ_TYPE(list->object), nsname->name);
+ break;
+ case OT_TYPETAG:
+ break;
+ case OT_NAMESPACE:
+ CError_FATAL(1854);
+ case OT_OBJECT:
+ CTemplClass_CopyObject(deduce, OBJECT(list->object));
+ break;
+ default:
+ CError_FATAL(1861);
+ }
+ }
+ }
+}
+
+static void CTemplClass_CopyUsingDecl(TypeDeduce *deduce, TypeTemplDep *type, AccessType access) {
+ TypeClass *tclass;
+ UInt32 qual = 0;
+
+ CError_ASSERT(1878, IS_TYPE_TEMPLATE(type) && type->dtype == TEMPLDEP_QUALNAME);
+
+ tclass = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, TYPE(type->u.qual.type), &qual));
+ if (!IS_TYPE_CLASS(tclass)) {
+ CError_Error(CErrorStr340, type->u.qual.name->name);
+ return;
+ }
+
+ CDecl_CompleteType(TYPE(tclass));
+ CScope_AddClassUsingDeclaration(TYPE_CLASS(deduce->inst), tclass, type->u.qual.name, access);
+}
+
+static void CTemplClass_CopyFriend(TypeDeduce *deduce, TemplateFriend *tfriend) {
+ TemplArg *arg;
+ Object *funcobj;
+ Boolean flag;
+ CScopeSave saveScope;
+ DeclInfo di;
+
+ CDecl_UnpackDeclInfo(&di, &tfriend->decl);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(di.thetype))
+ di.thetype = CTemplTool_DeduceTypeCopy(deduce, di.thetype, &di.qual);
+
+ if (di.expltargs) {
+ di.expltargs = CTemplTool_MakeGlobalTemplArgCopy(di.expltargs);
+ for (arg = di.expltargs; arg; arg = arg->next) {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
+ arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual);
+ break;
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
+ arg->data.paramdecl.expr = CTemplTool_DeduceExpr(deduce, arg->data.paramdecl.expr);
+ break;
+ case TPT_TEMPLATE:
+ default:
+ CError_FATAL(1930);
+ }
+ }
+ }
+
+ if (IS_TYPE_FUNC(di.thetype)) {
+ CScope_SetNameSpaceScope(CScope_FindGlobalNS(deduce->inst->theclass.nspace), &saveScope);
+ funcobj = CDecl_GetFunctionObject(&di, NULL, &flag, 0);
+ CScope_RestoreScope(&saveScope);
+
+ if (funcobj) {
+ CDecl_AddFriend(TYPE_CLASS(deduce->inst), funcobj, NULL);
+ if (tfriend->stream.tokens)
+ CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(deduce->inst), &tfriend->fileoffset, &tfriend->stream, 0);
+ } else {
+ CError_Error(CErrorStr201);
+ }
+ } else {
+ CError_ASSERT(1963, IS_TYPE_CLASS(di.thetype));
+ CDecl_AddFriend(TYPE_CLASS(deduce->inst), NULL, TYPE_CLASS(di.thetype));
+ }
+}
+
+Boolean CTempl_InstantiateTemplateClass(TypeClass *tclass) {
+ TemplClassInst *inst;
+ ParserTryBlock *tryBlock;
+ TemplateAction *action;
+ DefAction *defAction;
+ UInt8 saveAlignMode;
+
+ TypeDeduce deduce;
+ TemplStack stack;
+ CScopeSave saveScope;
+ ClassLayout layout;
+ TemplClass *templ;
+ TStreamElement *saveErrorRef;
+ TemplArg *inst_args;
+
+ CError_ASSERT(1989, tclass->flags & CLASS_IS_TEMPL_INST);
+
+ if (tclass->flags & CLASS_COMPLETED)
+ return 1;
+
+ inst = TEMPL_CLASS_INST(tclass);
+ if (inst->is_specialized)
+ return 0;
+
+ templ = inst->templ;
+ if (!(templ->flags & TEMPLCLASS_FLAGS_2))
+ templ = CTemplClass_GetMasterTemplate(templ);
+
+ if (templ->pspecs && CTemplClass_FindPartialTemplate(inst->inst_args, &templ, &inst_args)) {
+ CError_ASSERT(2013, !inst->oargs);
+ inst->templ = templ;
+ inst->oargs = inst->inst_args;
+ inst->inst_args = inst_args;
+ }
+
+ if (!(templ->theclass.flags & CLASS_COMPLETED))
+ return 0;
+
+ if (inst->is_instantiated)
+ return 0;
+
+ inst->is_instantiated = 1;
+ CScope_SetClassScope(tclass, &saveScope);
+ CTemplTool_PushInstance(&stack, tclass, NULL);
+
+ tryBlock = trychain;
+ trychain = NULL;
+
+ memclrw(&deduce, sizeof(deduce));
+ deduce.tmclass = templ;
+ deduce.inst = inst;
+ deduce.params = templ->templ__params;
+ deduce.args = inst->inst_args;
+
+ CError_ASSERT(2045, !templ->theclass.sominfo);
+ CError_ASSERT(2047, !templ->theclass.objcinfo);
+ CError_ASSERT(2049, !templ->theclass.vtable);
+
+ inst->theclass.flags |= templ->theclass.flags &
+ (CLASS_ABSTRACT | CLASS_SINGLE_OBJECT | CLASS_HAS_VBASES | CLASS_IS_CONVERTIBLE | CLASS_COM_OBJECT);
+
+ CTemplClass_CopyBaseClasses(&deduce, inst, templ);
+
+ deduce.x17 = (inst->theclass.flags & CLASS_HAS_VBASES) && !(templ->theclass.flags & CLASS_HAS_VBASES);
+
+ for (action = templ->actions; action; action = action->next) {
+ switch (action->type) {
+ case TAT_NESTEDCLASS:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyNestedClass(&deduce, action->u.tclasstype);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_ENUMTYPE:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyEnum(&deduce, action);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_FRIEND:
+ case TAT_ENUMERATOR:
+ case TAT_BASE:
+ case TAT_OBJECTINIT:
+ case TAT_USINGDECL:
+ case TAT_OBJECTDEF:
+ break;
+ default:
+ CError_FATAL(2094);
+ }
+ }
+
+ CTemplClass_CopyIVars(&deduce, inst, templ);
+ CTemplClass_CopyNameSpace(&deduce, inst, templ);
+
+ CError_ASSERT(2105, !templ->theclass.friends);
+
+ for (action = templ->actions; action; action = action->next) {
+ switch (action->type) {
+ case TAT_NESTEDCLASS:
+ break;
+ case TAT_ENUMTYPE:
+ for (defAction = deduce.defActions; defAction; defAction = defAction->next) {
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteEnumType(&deduce, action, defAction->enumtype);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ case TAT_FRIEND:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyFriend(&deduce, action->u.tfriend);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_ENUMERATOR:
+ break;
+ case TAT_BASE:
+ break;
+ case TAT_OBJECTINIT:
+ for (defAction = deduce.defActions; ; defAction = defAction->next) {
+ CError_ASSERT(2136, defAction);
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteObjectInit(&deduce, action, OBJECT(defAction->refobj));
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ case TAT_USINGDECL:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyUsingDecl(&deduce, action->u.usingdecl.type, action->u.usingdecl.access);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_OBJECTDEF:
+ for (defAction = deduce.defActions; ; defAction = defAction->next) {
+ CError_ASSERT(2156, defAction);
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteObject(&deduce, action, defAction->refobj);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ memclrw(&layout, sizeof(layout));
+ layout.lex_order_count = templ->lex_order_count;
+ layout.has_vtable = templ->flags & TEMPLCLASS_HAS_VTABLE;
+
+ saveAlignMode = copts.structalignment;
+ copts.structalignment = templ->align;
+ CDecl_CompleteClass(&layout, TYPE_CLASS(inst));
+ copts.structalignment = saveAlignMode;
+
+ if (templ->theclass.align > inst->theclass.align) {
+ inst->theclass.align = templ->theclass.align;
+ inst->theclass.size += CABI_StructSizeAlignValue(TYPE(inst), inst->theclass.size);
+ }
+
+ CTemplTool_PopInstance(&stack);
+ CScope_RestoreScope(&saveScope);
+ trychain = tryBlock;
+
+ return 1;
+}