#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_FLAGS_100); } 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_FLAGS_2 | FUNC_FLAGS_800000; 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, DeclE *de) { templ->lex_order_count = de->x8; if (de->xC) templ->flags |= TEMPLCLASS_FLAGS_1; templ->theclass.flags |= CLASS_FLAGS_2; } 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_FLAGS_800; 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.x60); di.x60 = *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.x60, 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_FLAGS_100; 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_FLAGS_2) && 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_FLAGS_100; templ->theclass.eflags = classDeclSpec; tk = lex(); if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100)) { 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_FLAGS_2) && 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_FLAGS_100; 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_FLAGS_20) 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_FLAGS_100000; if ( (TYPE_FUNC(dest->type)->flags & FUNC_FLAGS_1000) && 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_400000; dest->parent = src; if (IS_TYPE_FUNC(dest->object.type)) TYPE_FUNC(dest->object.type)->flags &= ~FUNC_FLAGS_2; 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_FLAGS_1000) && 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_FLAGS_40) { 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_FLAGS_100000; } else { dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); dest->qual |= Q_400000; if (IS_TYPE_FUNC(dest->type)) TYPE_FUNC(dest->type)->flags &= ~FUNC_FLAGS_2; switch (dest->datatype) { case DFUNC: case DVFUNC: CError_ASSERT(1769, IS_TYPE_FUNC(dest->type)); if (TYPE_FUNC(dest->type)->flags & FUNC_FLAGS_40) { 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_FLAGS_1000) && 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_10000 | 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; DeclE declE; TemplClass *templ; TStreamElement *saveErrorRef; TemplArg *inst_args; CError_ASSERT(1989, tclass->flags & CLASS_FLAGS_800); if (tclass->flags & CLASS_FLAGS_2) 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_FLAGS_2)) 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_FLAGS_ABSTRACT | CLASS_FLAGS_10 | CLASS_FLAGS_20 | CLASS_FLAGS_40 | CLASS_FLAGS_2000); CTemplClass_CopyBaseClasses(&deduce, inst, templ); deduce.x17 = (inst->theclass.flags & CLASS_FLAGS_20) && !(templ->theclass.flags & CLASS_FLAGS_20); 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(&declE, sizeof(declE)); declE.x8 = templ->lex_order_count; declE.xC = templ->flags & TEMPLCLASS_FLAGS_1; saveAlignMode = copts.structalignment; copts.structalignment = templ->align; CDecl_CompleteClass(&declE, 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; }