diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CTemplateNew.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CTemplateNew.c | 1880 |
1 files changed, 1880 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateNew.c b/compiler_and_linker/FrontEnd/C/CTemplateNew.c new file mode 100644 index 0000000..c33534a --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CTemplateNew.c @@ -0,0 +1,1880 @@ +#include "compiler/CTemplateNew.h" +#include "compiler/CBrowse.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.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/CTemplateClass.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +TemplClass *ctempl_templates; +TemplateFunction *ctempl_templatefuncs; +TemplStack *ctempl_curinstance; +static jmp_buf ctempl_parseparse; +static Boolean ctempl_scanfuncparams; + +// forward decls +static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex); +static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag); + +void CTempl_Setup(void) { + ctempl_curinstance = NULL; + ctempl_templates = NULL; + ctempl_templatefuncs = NULL; + ctempl_instdepth = 0; + ctempl_scanfuncparams = 0; +} + +void CTempl_Cleanup(void) { +} + +static short CTempl_MemberParseLex(void) { + switch ((tk = lex())) { + case ';': + case '=': + case '{': + case '}': + longjmp(ctempl_parseparse, 1); + } + + return tk; +} + +static void CTempl_MemberParseTemplArgList(void) { + struct { + char ch; + char flag; + } stack[256]; + int pos; + + stack[0].ch = '>'; + stack[0].flag = 1; + pos = 0; + while (1) { + switch (CTempl_MemberParseLex()) { + case '<': + if (stack[pos].flag) { + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = '>'; + stack[pos].flag = 1; + } + continue; + case '(': + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = ')'; + stack[pos].flag = 0; + continue; + case '[': + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = ']'; + stack[pos].flag = 0; + continue; + case '>': + if (!(stack[pos].flag)) + continue; + case ')': + case ']': + break; + default: + continue; + } + + if (tk != stack[pos].ch) + longjmp(ctempl_parseparse, 1); + if (--pos < 0) + break; + } +} + +static Type *CTempl_MemberParseTempl(HashNameNode *name) { + Type *type; + + type = CScope_GetTagType(cscope_current, name); + if (!type || !IS_TEMPL_CLASS(type)) + longjmp(ctempl_parseparse, 1); + + CTempl_MemberParseTemplArgList(); + if (lookahead() != TK_COLON_COLON) + return NULL; + CTempl_MemberParseLex(); + + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + switch (lookahead()) { + case '(': + case ')': + case ';': + case '=': + case '[': + return type; + case TK_COLON_COLON: + CTempl_MemberParseLex(); + continue; + default: + return NULL; + } + break; + case '~': + case TK_OPERATOR: + return type; + default: + return NULL; + } + } +} + +static Boolean CTempl_ParseTemplateMember(void) { + HashNameNode *name; + SInt32 state; + + CPrep_UnLex(); + CPrep_TokenStreamGetState(&state); + + if (setjmp(ctempl_parseparse) == 0) { + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + name = tkidentifier; + switch (lookahead()) { + case '<': + CTempl_MemberParseLex(); + if (CTempl_MemberParseTempl(name)) { + CError_FATAL(228); + return 1; + } + break; + case TK_COLON_COLON: + CTempl_MemberParseLex(); + while (1) { + if (CTempl_MemberParseLex() != TK_IDENTIFIER) + break; + if (lookahead() != TK_COLON_COLON) + break; + CTempl_MemberParseLex(); + } + break; + } + break; + case 0: + return 0; + default: + continue; + } + break; + } + + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + name = tkidentifier; + if (CTempl_MemberParseLex() == '<') { + if (CTempl_MemberParseTempl(name)) { + CError_FATAL(265); + return 1; + } + } + break; + case 0: + return 0; + default: + continue; + } + break; + } + } + + CPrep_TokenStreamSetState(&state); + tk = lex(); + return 0; +} + +static Type *CTempl_ParseTemplArgType(UInt32 *resultQual) { + DeclInfo di; + + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.storageclass) + CError_Error(CErrorStr177); + if (di.x48) + CError_Error(CErrorStr121); + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_REFERENCE | Q_ALIGNED_MASK)); + + scandeclarator(&di); + if (di.name) + CError_Error(CErrorStr121); + + CTemplTool_CheckTemplArgType(di.thetype); + + *resultQual = di.qual; + return di.thetype; +} + +static ENode *CTempl_ParseTemplArgExpr(Type *type, UInt32 qual) { + ENode *expr; + ENode *copy; + + disallowgreaterthan = 1; + if (copts.old_argmatch) + expr = conv_assignment_expression(); + else + expr = assignment_expression(); + disallowgreaterthan = 0; + + if (type && !CTemplTool_IsTemplateArgumentDependentType(type) && !IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { + expr = argumentpromotion(expr, type, qual, 1); + if (IS_TYPE_POINTER_ONLY(type)) { + if (ENODE_IS(expr, ETYPCON) && ENODE_IS(expr->data.monadic, EINTCONST)) + expr = expr->data.monadic; + if (ENODE_IS(expr, EINTCONST)) + expr->rtype = type; + } + } + + if (!IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { + if (!copts.old_argmatch) + expr = pointer_generation(expr); + + switch (expr->type) { + case EINTCONST: + break; + case EOBJREF: + if (CParser_HasInternalLinkage2(expr->data.objref)) + CError_Error(CErrorStr357); + break; + case EOBJLIST: + CError_Error(CErrorStr199); + expr = nullnode(); + break; + default: + CError_Error(CErrorStr371); + expr = nullnode(); + } + + copy = galloc(sizeof(ENode)); + *copy = *expr; + return copy; + } else { + return CInline_CopyExpression(expr, CopyMode1); + } +} + +static Type *CTempl_ParseTemplArgTempl(TemplParam *params) { + NameResult pr; + + if ( + (tk != TK_IDENTIFIER && tk != TK_COLON_COLON) || + !CScope_ParseDeclName(&pr) || + !pr.type + ) + { + CError_Error(CErrorStr121); + tk = lex(); + return NULL; + } + + if (IS_TEMPL_CLASS(pr.type)) { + if (params && !CTemplTool_EqualParams(params->data.templparam.plist, TEMPL_CLASS(pr.type)->templ__params, 0)) { + CError_Error(CErrorStr235); + tk = lex(); + return NULL; + } + } else { + if (!CTemplTool_IsTemplateArgumentDependentType(pr.type)) + CError_Error(CErrorStr146); + } + + tk = lex(); + return pr.type; +} + +static UInt8 CTempl_GetTemplateNestIndex(NameSpace *nspace) { + UInt8 count = 0; + + while (nspace) { + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_ANY)) + count++; + nspace = nspace->parent; + } + + return count; +} + +static TemplParam *CTempl_ParseParam(NameSpace *nspace, TemplParam *param, UInt16 index, UInt8 nindex) { + DeclInfo di; + SInt32 savedState; + short startToken; + + param = galloc(sizeof(TemplParam)); + memclrw(param, sizeof(TemplParam)); + + param->pid.index = index; + param->pid.nindex = nindex; + + CPrep_TokenStreamGetState(&savedState); + + switch ((startToken = tk)) { + case TK_CLASS: + case TK_TYPENAME: + if ((tk = lex()) == TK_IDENTIFIER) { + param->name = tkidentifier; + tk = lex(); + } + + switch (tk) { + case ',': + case '>': + break; + case '=': + tk = lex(); + param->data.typeparam.type = CTempl_ParseTemplArgType(¶m->data.typeparam.qual); + break; + default: + param->name = NULL; + CPrep_TokenStreamSetState(&savedState); + tk = startToken; + goto defaultProc; + } + + param->pid.type = TPT_TYPE; + break; + + case TK_TEMPLATE: + if ((tk = lex()) != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + tk = lex(); + param->data.templparam.plist = CTempl_ParseParamList(nspace, 0); + + if (tk == '>') + tk = lex(); + else + CError_Error(CErrorStr231); + + if (tk == TK_CLASS) + tk = lex(); + else + CError_Error(CErrorStr121); + + if (tk == TK_IDENTIFIER) { + param->name = tkidentifier; + tk = lex(); + } + + if (tk == '=') { + tk = lex(); + param->data.templparam.defaultarg = CTempl_ParseTemplArgTempl(param); + } + + param->pid.type = TPT_TEMPLATE; + break; + + default: + defaultProc: + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.storageclass) + CError_Error(CErrorStr177); + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_REFERENCE | Q_ALIGNED_MASK)); + + scandeclarator(&di); + + switch (di.thetype->type) { + case TYPEARRAY: + di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype)); + break; + case TYPEFUNC: + di.thetype = CDecl_NewPointerType(di.thetype); + break; + case TYPEMEMBERPOINTER: + CError_Error(CErrorStr190); + di.thetype = TYPE(&stsignedint); + break; + case TYPEINT: + case TYPEENUM: + case TYPETEMPLATE: + case TYPEPOINTER: + break; + default: + CError_Error(CErrorStr229); + di.thetype = TYPE(&stsignedint); + } + + di.thetype = CParser_RemoveTopMostQualifiers(di.thetype, &di.qual); + param->name = di.name; + param->data.paramdecl.type = di.thetype; + param->data.paramdecl.qual = di.qual; + if (tk == '=') { + tk = lex(); + param->data.paramdecl.defaultarg = CTempl_ParseTemplArgExpr(di.thetype, di.qual); + } + + param->pid.type = TPT_NONTYPE; + break; + } + + if (param->name) + CTemplTool_InsertTemplateParameter(nspace, param); + + return param; +} + +static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex) { + TemplParam *params; + TemplParam **ptr; + TemplParam *param; + TemplParam *scan; + UInt16 index; + + params = NULL; + index = 0; + ptr = ¶ms; + + while (1) { + param = CTempl_ParseParam(nspace, params, index, nindex); + if (!param) + break; + + if (param->name) { + for (scan = params; scan; scan = scan->next) { + if (scan->name == param->name) + CError_Error(CErrorStr122, param->name->name); + } + } + + *ptr = param; + ptr = ¶m->next; + + if (tk != ',') + break; + + tk = lex(); + index++; + } + + if (!params) + CError_Error(CErrorStr229); + + return params; +} + +TemplArg *CTempl_ParseUncheckTemplArgs(TemplParam *params, Boolean is_global) { + TemplArg *args; + TemplArg *last; + UInt16 index; + + if (tk != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + if ((tk = lex()) == '>') + return NULL; + + args = NULL; + index = 0; + while (1) { + if (is_global) { + if (args) { + last->next = galloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + args = last; + } + } else { + if (args) { + last->next = lalloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + args = last; + } + } + + last->next = NULL; + + if (!params) { + Type *type; + UInt32 qual; + Boolean flag; + + last->pid.index = index; + last->pid.nindex = 0; + + if ((type = CParser_ParseTypeID(&qual, &flag))) { + if (flag) { + last->data.ttargtype = type; + last->pid.type = TPT_TEMPLATE; + } else { + last->data.typeparam.type = type; + last->data.typeparam.qual = qual; + last->pid.type = TPT_TYPE; + } + } else { + last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0); + last->pid.type = TPT_NONTYPE; + } + } else { + last->pid = params->pid; + switch (last->pid.type) { + case TPT_TYPE: + last->data.typeparam.type = CTempl_ParseTemplArgType(&last->data.typeparam.qual); + break; + case TPT_NONTYPE: + last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0); + break; + case TPT_TEMPLATE: + if (!(last->data.ttargtype = CTempl_ParseTemplArgTempl(params))) + return NULL; + break; + default: + CError_FATAL(674); + } + params = params->next; + } + + if (tk == '>') + return args; + + if (tk != ',') { + CError_Error(CErrorStr116); + return NULL; + } + + tk = lex(); + index++; + } +} + +static TemplArg *CTempl_ParseTemplArgs(TemplClass **resultTempl, TemplArg **resultArgs) { + TemplParam *param; + TemplParam *params; + TemplArg *args; + TemplArg **ptr; + TemplArg *arg; + + params = (*resultTempl)->templ__params; + *resultArgs = NULL; + + if (tk != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + tk = lex(); + + param = params; + args = NULL; + ptr = &args; + + while (param) { + arg = galloc(sizeof(TemplArg)); + memclrw(arg, sizeof(TemplArg)); + + *ptr = arg; + ptr = &arg->next; + + arg->pid = param->pid; + + if (tk != '>') { + switch (arg->pid.type) { + case TPT_TYPE: + arg->data.typeparam.type = CTempl_ParseTemplArgType(&arg->data.typeparam.qual); + break; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) { + Type *type; + UInt32 qual; + + type = CTemplTool_DeduceArgDepType(args, param->data.paramdecl.type, param->data.paramdecl.qual, &qual); + arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(type, qual); + } else { + arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(param->data.paramdecl.type, param->data.paramdecl.qual); + } + break; + + case TPT_TEMPLATE: + if (!(arg->data.ttargtype = CTempl_ParseTemplArgTempl(param))) + return NULL; + break; + + default: + CError_FATAL(742); + } + + if (tk != '>') { + if (tk != ',') { + CError_Error(CErrorStr232); + return NULL; + } + + if ((tk = lex()) == '>') { + CError_Error(CErrorStr232); + return NULL; + } + } + } else { + switch (arg->pid.type) { + case TPT_TYPE: + if (!param->data.typeparam.type) { + CError_Error(CErrorStr232); + return NULL; + } + + arg->data.typeparam.type = param->data.typeparam.type; + arg->data.typeparam.qual = param->data.typeparam.qual; + + if (CTemplTool_IsTemplateArgumentDependentType(param->data.typeparam.type)) { + TypeDeduce deduce; + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = *resultTempl; + deduce.inst = NULL; + deduce.params = params; + deduce.args = args; + + arg->data.typeparam.qual = param->data.typeparam.qual; + arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(&deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); + } + break; + + case TPT_NONTYPE: + if (!param->data.paramdecl.defaultarg) { + CError_Error(CErrorStr232); + return NULL; + } + + if (IS_TYPE_TEMPLDEPEXPR(param->data.paramdecl.defaultarg->rtype)) { + TypeDeduce deduce; + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = *resultTempl; + deduce.inst = NULL; + deduce.params = params; + deduce.args = args; + + arg->data.paramdecl.expr = CInline_CopyExpression( + CTemplTool_DeduceExpr(&deduce, param->data.paramdecl.defaultarg), CopyMode1); + } else { + arg->data.paramdecl.expr = param->data.paramdecl.defaultarg; + } + break; + + case TPT_TEMPLATE: + if (!param->data.templparam.defaultarg) { + CError_Error(CErrorStr232); + return NULL; + } + + if (IS_TEMPL_CLASS(param->data.templparam.defaultarg)) { + arg->data.ttargtype = param->data.templparam.defaultarg; + break; + } + + if (CTemplTool_IsTemplateArgumentDependentType(param->data.templparam.defaultarg)) { + CError_Error(CErrorStr190); + return NULL; + } + + CError_FATAL(817); + + default: + CError_FATAL(820); + } + } + + param = param->next; + } + + if (tk != '>') { + CError_Error(CErrorStr231); + return NULL; + } + + if ((*resultTempl)->pspecs) + return args; + + return args; +} + +Type *CTempl_ParseTemplTemplParam(TypeTemplDep *type) { + TemplArg *args; + Type *newType; + + tk = lex(); + if (!(args = CTempl_ParseUncheckTemplArgs(NULL, 1))) { + CError_Error(CErrorStr121); + return TYPE(&stsignedint); + } + + newType = CDecl_NewTemplDepType(TEMPLDEP_QUALTEMPL); + TYPE_TEMPLATE(newType)->u.qualtempl.type = type; + TYPE_TEMPLATE(newType)->u.qualtempl.args = args; + return newType; +} + +Type *CTempl_ClassGetType(TemplClass *templ) { + TemplClass *owner; + TemplArg *ownerArgs; + TemplArg *args; + Type *type; + + owner = templ; + if (templ->pspec_owner) + owner = templ->pspec_owner; + + if (!(args = CTempl_ParseTemplArgs(&owner, &ownerArgs))) + return &stvoid; + + if ((type = CTemplTool_IsDependentTemplate(owner, args))) + return type; + + return TYPE(CTemplClass_GetInstance(owner, args, ownerArgs)); +} + +static void CTempl_SetupClassParamNameSpace(DeclFucker *what_is_this, TypeClass *tclass) { + cscope_current = tclass->nspace; +} + +Boolean CTempl_IsQualifiedMember(DeclInfo *di, Type *type, NameSpace **resultnspace) { + if ( + TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME && + (type = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type))) + ) + { + *resultnspace = TYPE_CLASS(type)->nspace; + CError_ASSERT(948, di->fucker34 && (*resultnspace)->theclass); + + CTempl_SetupClassParamNameSpace(di->fucker34, (*resultnspace)->theclass); + di->fucker34 = NULL; + return 1; + } + + return 0; +} + +static void *CTempl_ParseMemberFunction(int unk1, int unk2, int unk3, Object *func) { + // no idea what should've been here, it's not called + + CError_ASSERT(974, TYPE_FUNC(func->type)->flags & FUNC_METHOD); + + return NULL; +} + +static void CTempl_ParseMember(TemplParam *params, TemplClass *templ, DeclInfo *di, SInt32 *startOffset) { + Object *object; + NameSpaceObjectList *nsol; + TokenStream stream; + CPrepFileInfo *file; + SInt32 offset; + Boolean saveForceLoc; + TemplateMember *member; + + if (templ->theclass.flags & CLASS_IS_TEMPL) + di->thetype = CTemplTool_ResolveMemberSelfRefs(templ, di->thetype, &di->qual); + + if (IS_TYPE_FUNC(di->thetype)) { + Boolean flag; + if (!(object = CDecl_GetFunctionObject(di, NULL, &flag, 0))) { + CError_Error(CErrorStr140, di->name->name); + return; + } + + if (tk != '{' && tk != TK_TRY && tk != ':') { + if (tk != ';') + CError_Error(CErrorStr123); + else + tk = lex(); + return; + } + + if ( + (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) && + (!(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) || object->u.func.u.templ->instances) + ) + CError_Error(CErrorStr333, object); + + TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL_INSTANCE | FUNC_DEFINED; + + CPrep_StreamGetBlock(&stream, NULL, 1); + saveForceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + CPrep_BrowserFilePosition(&file, &offset); + gForceSourceLoc = saveForceLoc; + + if (file && file->recordbrowseinfo && *startOffset >= 0 && offset > *startOffset) + CBrowse_NewFunction(object, file, file, *startOffset, offset + 1); + } else { + if (!(nsol = CScope_GetLocalObject(templ->theclass.nspace, di->name))) { + CError_Error(CErrorStr140, di->name->name); + return; + } + + object = OBJECT(nsol->object); + if (object->otype != OT_OBJECT) { + CError_Error(CErrorStr122, di->name->name); + return; + } + + if ( + !is_typesame(di->thetype, object->type) || + (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL)) != (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL)) + ) + { + CError_Error(CErrorStr249, CError_GetObjectName(object), object->type, object->qual, di->thetype, di->qual); + return; + } + + CError_ASSERT(1070, object->datatype == DDATA); + + CPrep_StreamGetSemicolon(&stream, NULL); + } + + if (stream.tokens) { + if (IS_TEMPL_FUNC(object->type) != 0) { + if (!CTemplTool_EqualParams(object->u.func.u.templ->params, params, 0)) + CError_Error(CErrorStr235); + + object->u.func.u.templ->stream = stream; + } else { + if (!(templ->theclass.flags & CLASS_IS_TEMPL)) { + CError_Error(CErrorStr190); + return; + } + + member = CTemplClass_DefineMember(templ, object, &cparser_fileoffset, &stream); + if (templ->templ__params) { + if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) { + CError_Error(CErrorStr235); + return; + } + + member->params = params; + } + } + } +} + +static TemplateFunction *CTempl_DeclareTemplateFunction(DeclInfo *di, TemplParam *params, TypeClass *tclass, AccessType access, Boolean flag) { + TemplateFunction *templ; + Object *object; + + if (tclass) { + CError_ASSERT(1122, cscope_current->theclass); + di->thetype = TYPE(CDecl_MakeTypeMemberFunc(TYPE_FUNC(di->thetype), cscope_current->theclass, flag)); + } else { + access = ACCESSPUBLIC; + } + + templ = galloc(sizeof(TemplateFunction)); + memclrw(templ, sizeof(TemplateFunction)); + + templ->next = ctempl_templatefuncs; + ctempl_templatefuncs = templ; + + templ->params = params; + templ->name = di->name; + templ->deftoken = symdecltoken; + + object = CParser_NewFunctionObject(NULL); + object->access = access; + object->name = di->name; + object->u.func.linkname = CParser_GetUniqueName(); + object->type = di->thetype; + object->qual = di->qual | Q_MANGLE_NAME; + object->sclass = di->storageclass; + TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL; + object->u.func.u.templ = templ; + + if (di->qual & Q_INLINE) + object->sclass = TK_STATIC; + + templ->tfunc = object; + CScope_AddObject(cscope_current, di->name, OBJ_BASE(object)); + + return templ; +} + +static void CTempl_ParseTemplateFunction(TemplateFunction *templ, TypeClass *tclass, SInt32 *startOffset) { + Object *object; + CPrepFileInfo *file; + SInt32 offset; + Boolean saveForceLoc; + + object = templ->tfunc; + + if (tk == '{' || tk == ':' || tk == TK_TRY) { + if (tclass) { + object->qual |= Q_INLINE; + object->sclass = TK_STATIC; + } + + if (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + CError_Error(CErrorStr333, object); + + TYPE_FUNC(object->type)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE; + + CPrep_StreamGetBlock(&templ->stream, NULL, 0); + + if (lookahead() == ';') + tk = lex(); + else + tk = ';'; + + saveForceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + CPrep_BrowserFilePosition(&file, &offset); + gForceSourceLoc = saveForceLoc; + + if (file && *startOffset >= 0 && offset > *startOffset) { + templ->srcfile = file; + templ->startoffset = *startOffset; + templ->endoffset = offset + 1; + if (cparamblkptr->browseoptions.recordTemplates && file->recordbrowseinfo) + CBrowse_NewTemplateFunc(templ); + } + + } else { + if (tk != ';') + CError_Error(CErrorStr121); + } +} + +static HashNameNode *CTempl_FindConversionFuncName(TypeClass *tclass, Type *type, UInt32 qual) { + Object *object; + CScopeObjectIterator iter; + + CScope_InitObjectIterator(&iter, tclass->nspace); + do { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + return NULL; + } while ( + !IS_TYPE_FUNC(object->type) || + !(TYPE_FUNC(object->type)->flags & FUNC_CONVERSION) || + (TYPE_FUNC(object->type)->qual & (Q_CONST | Q_VOLATILE)) != (qual & (Q_CONST | Q_VOLATILE)) || + !is_typesame(TYPE_FUNC(object->type)->functype, type) + ); + + return object->name; +} + +static void CTempl_ParseConversionFunctionTemplate(DeclInfo *di, DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access) { + tk = lex(); + if (!tclass) { + CError_Error(CErrorStr121); + return; + } + + tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; + CError_QualifierCheck(di->qual & ~Q_INLINE); + + conversion_type_name(di); + CDecl_NewConvFuncType(di); + + if (cscope_current->is_templ) { + CError_ASSERT(1260, cscope_current == what_is_this->nspace); + cscope_current = what_is_this->nspace->parent; + } + + CTempl_ParseTemplateFunction(CTempl_DeclareTemplateFunction(di, params, tclass, access, 0), tclass, startOffset); +} + +static void CTempl_ParseFunctionOrMemberTemplate(DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access, Boolean mysteryFlag) { + NameSpaceObjectList *nsol; + Object *object; + TemplParam *param; + TemplateFunction *templfunc; + Boolean disallowCVFlag; + TypeClass *tclass2; + Type *type; + UInt32 qual; + DeclInfo di; + + for (param = params; param; param = param->next) { + switch (param->pid.type) { + case TPT_TYPE: + if (param->data.typeparam.type) { + CError_Error(CErrorStr378); + param->data.typeparam.type = NULL; + } + break; + case TPT_NONTYPE: + if (param->data.paramdecl.defaultarg) { + CError_Error(CErrorStr378); + param->data.paramdecl.defaultarg = NULL; + } + break; + case TPT_TEMPLATE: + if (param->data.templparam.defaultarg) { + CError_Error(CErrorStr378); + param->data.templparam.defaultarg = NULL; + } + break; + default: + CError_FATAL(1317); + } + } + + disallowCVFlag = 0; + ctempl_scanfuncparams = 1; + + memclrw(&di, sizeof(di)); + di.x51 = mysteryFlag; + + if (tk == TK_OPERATOR) { + CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access); + return; + } + + CParser_GetDeclSpecs(&di, 1); + if (tk == ';' && IS_TEMPL_CLASS(di.thetype)) + return; + + if (di.x10 || di.x14) { + TypeFunc *tfunc; + + if (di.x14) { + di.x10 = OBJECT(di.x14->object); + CError_ASSERT(1342, di.x10->otype == OT_OBJECT); + } + + CError_ASSERT(1344, IS_TYPE_FUNC(di.x10->type)); + + tfunc = TYPE_FUNC(di.x10->type); + if (tfunc->flags & FUNC_CONVERSION) { + di.thetype = tfunc->functype; + di.qual |= tfunc->qual; + di.nspace = di.x10->nspace; + di.name = di.x10->name; + } else if (tfunc->flags & FUNC_IS_CTOR) { + di.thetype = TYPE(&void_ptr); + di.nspace = di.x10->nspace; + di.name = di.x10->name; + } else { + CError_Error(CErrorStr121); + return; + } + + if ((tk = lex()) == '(') { + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + if (IS_TYPE_FUNC(di.thetype)) + goto skipPastStuff; + } else { + CError_Error(CErrorStr114); + } + } + + if (di.storageclass) { + if (tclass) { + if (di.storageclass == TK_STATIC) + disallowCVFlag = 1; + else + CError_Error(CErrorStr177); + di.storageclass = 0; + } else { + if (di.storageclass != TK_STATIC && di.storageclass != TK_EXTERN) { + CError_Error(CErrorStr177); + di.storageclass = 0; + } + } + } + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_ASM | Q_PASCAL | Q_INLINE | Q_EXPLICIT | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)); + + if (tk == TK_OPERATOR && di.x4A) { + CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access); + return; + } + + if (!di.x53) { + if (tclass && IS_TYPE_CLASS(di.thetype) && TYPE_CLASS(di.thetype) == tclass && tk == '(') { + CError_ASSERT(1418, cscope_current == tclass->nspace); + CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_EXPLICIT)); + + di.thetype = TYPE(&void_ptr); + di.x4B = 1; + + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + if (TYPE_FUNC(di.thetype)->args && !TYPE_FUNC(di.thetype)->args->next && TYPE_FUNC(di.thetype)->args->type == TYPE(tclass)) { + CError_Error(CErrorStr239); + TYPE_FUNC(di.thetype)->args = NULL; + } + + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR; + di.name = constructor_name_node; + + what_is_this->nspace->tparams = NULL; + + CTempl_ParseTemplateFunction( + CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag), + tclass, startOffset); + + return; + } else { + CError_Error(CErrorStr241); + } + } + + if (IS_TYPE_TEMPLATE(di.thetype)) { + if ( + tk == '(' && + TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME && + (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(di.thetype)->u.qual.type)))) && + TYPE_TEMPLATE(di.thetype)->u.qual.name == tclass2->classname + ) + { + if (tclass) + CError_Error(CErrorStr229); + + di.thetype = TYPE(&void_ptr); + di.x4B = 1; + + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + di.name = constructor_name_node; + if (tclass2->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR; + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr241); + } + + return; + } + + if ( + tk == TK_COLON_COLON && + TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_TEMPLATE && + (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(di.thetype))) + ) + { + if (tclass) + CError_Error(CErrorStr229); + + if ((tk = lex()) == '~') { + if ( + (tk = lex()) != TK_IDENTIFIER || + tkidentifier != tclass2->classname || + (tk = lex()) != '(' + ) + { + if (tk == '<') { + DeclInfo di2; + + CPrep_UnLex(); + tk = TK_IDENTIFIER; + tkidentifier = tclass2->classname; + + memclrw(&di2, sizeof(di2)); + CParser_GetDeclSpecs(&di2, 0); + if (tk != '(') + CError_Error(CErrorStr241); + + if (di2.thetype != TYPE(tclass2) && (!IS_TYPE_TEMPLATE(di2.thetype) || CTemplTool_IsTemplate( + TYPE_TEMPLATE(di2.thetype)) != TEMPL_CLASS(tclass2))) + { + CError_Error(CErrorStr241); + } + } else { + CError_Error(CErrorStr241); + } + } + + di.thetype = TYPE(&void_ptr); + + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + if (tclass2->sominfo) + di.qual |= Q_VIRTUAL; + else + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + di.name = destructor_name_node; + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_DTOR; + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr241); + } + } else if (tk == TK_OPERATOR) { + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + if (CMangler_OperatorName((tk = lex()))) { + CError_Error(CErrorStr349); + return; + } + + CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_VIRTUAL)); + conversion_type_name(&di); + + type = di.thetype; + qual = di.qual; + CDecl_NewConvFuncType(&di); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + di.name = CTempl_FindConversionFuncName(tclass2, type, qual); + if (!di.name) { + CError_Error(CErrorStr150, "conversion function"); + return; + } + } + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr121); + } + + return; + } + + if (TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME && !di.x49) + CError_Warning(CErrorStr355); + } + } + + di.x30 = params; + di.fucker34 = what_is_this; + scandeclarator(&di); + ctempl_scanfuncparams = 0; + +skipPastStuff: + if (cscope_current->is_templ) { + CError_ASSERT(1589, cscope_current == what_is_this->nspace); + what_is_this->nspace->tparams = NULL; + } + + if (!di.name) { + CError_Error(CErrorStr229); + return; + } + + if (di.nspace) { + if (di.nspace->theclass) { + if (tclass) + CError_Error(CErrorStr229); + CTempl_ParseMember(params, TEMPL_CLASS(di.nspace->theclass), &di, startOffset); + return; + } + + if (!IS_TYPE_FUNC(di.thetype)) { + CError_Error(CErrorStr229); + return; + } + + CScope_FindName(di.nspace, di.name); + } else { + if (!IS_TYPE_FUNC(di.thetype)) { + CError_Error(CErrorStr229); + return; + } + + CScope_FindName(cscope_current, di.name); + } + + nsol = CScope_FindName(di.nspace ? di.nspace : cscope_current, di.name); + while (nsol) { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TEMPL_FUNC(object->type)) { + templfunc = CTemplTool_GetFuncTempl(object); + if (CTemplTool_EqualParams(templfunc->params, params, 0) && is_typesame(object->type, di.thetype)) { + if (tk != ';' && templfunc->stream.tokens) + CError_Error(CErrorStr234); + + if (tk == '{' || tk == ':' || tk == TK_TRY) + CError_ASSERT(1654, CTemplTool_EqualParams(templfunc->params, params, 1)); + + if (di.qual & Q_INLINE) + object->qual |= Q_INLINE; + TYPE_FUNC(object->type)->args = TYPE_FUNC(di.thetype)->args; + break; + } + } + nsol = nsol->next; + } + + if (!nsol) { + if (di.nspace) + CError_Error(CErrorStr229); + templfunc = CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag); + } + + CTempl_ParseTemplateFunction(templfunc, tclass, startOffset); +} + +static void CTempl_ExplicitInstantiation(void) { + Boolean flag; + short saveToken; + Object *object; + DeclInfo di; + + memclrw(&di, sizeof(di)); + di.x51 = 1; + flag = 1; + + if (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__dont_instantiate")) { + flag = 0; + tk = lex(); + } + + switch (tk) { + case TK_STRUCT: + case TK_UNION: + case TK_CLASS: + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + if (tk == ';') { + if (IS_TEMPL_CLASS_INST(di.thetype)) { + CTempl_InstantiateTemplateClass(TYPE_CLASS(di.thetype)); + if ((TYPE_CLASS(di.thetype)->flags & CLASS_COMPLETED) && !(TYPE_CLASS(di.thetype)->eflags & CLASS_EFLAGS_IMPORT)) { + if (flag) + CTempl_GenClassInstance(TEMPL_CLASS_INST(di.thetype), 1); + else + TEMPL_CLASS_INST(di.thetype)->is_extern = 1; + } else { + CError_Error(CErrorStr136, TYPE_CLASS(di.thetype), 0); + } + } else { + CError_Error(CErrorStr238); + } + return; + } + break; + default: + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + } + + di.x51 = 1; + + scandeclarator(&di); + + saveToken = tk; + + di.x38 = NULL; + if ( + di.name && + IS_TYPE_FUNC(di.thetype) && + (object = CDecl_GetFunctionObject(&di, di.nspace, NULL, 1)) && + IS_TYPE_FUNC(object->type) && + object->u.func.inst && + di.x38 + ) + { + if (!flag) + object->u.func.inst->is_extern = 1; + else + CTempl_GenFuncInstance(di.x38, object->u.func.inst, 1); + } else { + CError_Error(CErrorStr238); + } + + if (saveToken != ';') + CError_Error(CErrorStr123); +} + +static void CTempl_ExplicitSpecialization(void) { + Boolean flag; + TemplParam *params; + int counter; + DeclFucker what_is_this; + DeclInfo di; + + flag = 0; + counter = 1; + while (tk == TK_TEMPLATE) { + if ((tk = lex()) != '<') { + CError_Error(CErrorStr230); + break; + } + + if ((tk = lex()) != '>') { + if (!flag) { + what_is_this.nspace = cscope_current; + what_is_this.mystery4 = NULL; + cscope_current->tparams = NULL; + flag = 1; + } + + params = CTempl_ParseParamList(what_is_this.nspace, counter); + if (tk != '>') + CError_Error(CErrorStr231); + } else { + if (flag) + CError_Error(CErrorStr335); + } + + counter++; + tk = lex(); + } + + if (flag) { + SInt32 startOffset = -1; + CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, NULL, &startOffset, ACCESSPUBLIC, 1); + return; + } + + memclrw(&di, sizeof(di)); + di.x3C = counter; + di.x51 = 1; + CParser_GetDeclSpecs(&di, 1); + + if (tk == ';') { + if (IS_TEMPL_CLASS_INST(di.thetype)) + TEMPL_CLASS_INST(di.thetype)->is_specialized = 1; + else + CError_Error(CErrorStr335); + } else { + scandeclaratorlist(&di); + if ((tk != ';' && tk != '}') || di.x3C) + CError_Error(CErrorStr335); + } + + if (flag) + what_is_this.nspace->tparams = NULL; +} + +void CTempl_Parse(TemplClass *templ, AccessType access) { + TemplParam *params; + UInt8 i; + short mode; + Boolean flag; + UInt8 classDeclSpec; + SInt32 startOffset; + SInt32 savedState; + CScopeSave savedScope; + DeclFucker what_is_this; + + startOffset = CPrep_BrowserFileOffset(); + CScope_GetScope(&savedScope); + + if ((tk = lex()) != '<') { + if (templ) + CError_Error(CErrorStr238); + CTempl_ExplicitInstantiation(); + CScope_RestoreScope(&savedScope); + return; + } + + if ((tk = lex()) == '>') { + if (templ) + CError_Error(CErrorStr335); + tk = lex(); + CTempl_ExplicitSpecialization(); + CScope_RestoreScope(&savedScope); + return; + } + + what_is_this.nspace = cscope_current; + what_is_this.mystery4 = NULL; + cscope_current->tparams = NULL; + i = CTempl_GetTemplateNestIndex(what_is_this.nspace); + + while (1) { + params = CTempl_ParseParamList(what_is_this.nspace, i); + if (tk != '>') + CError_Error(CErrorStr231); + + if ((tk = lex()) != TK_TEMPLATE) + break; + + if (templ) + CError_Error(CErrorStr121); + + if ((tk = lex()) != '<') + CError_Error(CErrorStr230); + else + tk = lex(); + + i++; + } + + switch (tk) { + case TK_CLASS: + mode = CLASS_MODE_CLASS; + break; + case TK_UNION: + mode = CLASS_MODE_UNION; + break; + case TK_STRUCT: + mode = CLASS_MODE_STRUCT; + break; + default: + mode = -1; + } + + if (mode >= 0) { + classDeclSpec = 0; + flag = 0; + + CPrep_TokenStreamGetState(&savedState); + if ((tk = lex()) == TK_UU_DECLSPEC) + CDecl_ParseClassDeclSpec(&classDeclSpec); + + if (tk == TK_IDENTIFIER) { + if ((tk = lex()) == '<') { + if (setjmp(ctempl_parseparse) == 0) { + CTempl_MemberParseTemplArgList(); + flag = 1; + tk = lex(); + } + } + + switch (tk) { + case ':': + case ';': + case '{': + CPrep_TokenStreamSetCurState(&savedState); + if (flag) + CTemplClass_ParsePartialSpecialization(&what_is_this, params, mode, &startOffset); + else + CTemplClass_ParseClass(&what_is_this, params, mode, &startOffset); + goto done; + } + } + + CPrep_TokenStreamSetCurState(&savedState); + } + + CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, TYPE_CLASS(templ), &startOffset, access, 0); + +done: + what_is_this.nspace->tparams = NULL; + CScope_RestoreScope(&savedScope); +} + +void CTempl_ParseInstanceScopeFunction(Object *funcobj, TemplClassInst *inst, TypeClass *tclass) { + TemplParam *params; + NameSpace *nspace; + TemplateMember *member; + Object *parent; + DeclInfo di; + CScopeSave savedScope; + TemplStack stack; + + params = inst->templ->templ__params; + if (funcobj->qual & Q_IS_TEMPLATED) { + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members, parent = OBJECT_TEMPL(funcobj)->parent; member; member = member->next) { + if (member->object == parent) { + if (member->params) + params = member->params; + break; + } + } + } + + CTemplTool_PushInstance(&stack, NULL, funcobj); + nspace = CTemplTool_InsertTemplateArgumentNameSpace(params, inst, &savedScope); + if (tclass) + cscope_current = tclass->nspace; + + memclrw(&di, sizeof(di)); + CFunc_ParseFuncDef(funcobj, &di, NULL, 0, 0, tclass ? cscope_current : NULL); + + CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope); + CTemplTool_PopInstance(&stack); +} + +Boolean CTempl_GenFuncInstance(TemplateFunction *templ, TemplFuncInstance *inst, Boolean flag) { + Boolean saveDebugInfo; + NameSpace *nspace; + SInt32 streamState; + TemplStack stack; + DeclInfo di; + + if (!flag && copts.no_implicit_templates && inst->object->sclass != TK_STATIC) + return 0; + + if (inst->is_extern && !flag) + return 0; + + while (1) { + if (templ->stream.tokens) + break; + if (!templ->unk4) + break; + templ = templ->unk4; + } + + if (!templ->stream.tokens) { + if (flag) { + CError_SetErrorToken(&templ->deftoken); + CError_Error(CErrorStr233, inst->object); + } + return 0; + } + + inst->is_instantiated = 1; + + CPrep_StreamInsert(&templ->stream, &streamState); + + saveDebugInfo = copts.filesyminfo; + if (copts.nosyminline || !templ->deftoken.tokenfile) + copts.filesyminfo = 0; + + CError_ASSERT(2112, (tk = lex()) == '{' || tk == ':' || tk == TK_TRY); + + symdecltoken = *CPrep_CurStreamElement(); + + if (copts.filesyminfo) { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, &templ->deftoken); + symdecloffset = cparser_fileoffset.tokenline; + } + + if (inst->object->sclass != TK_STATIC) + inst->object->qual |= Q_WEAK; + + memclrw(&di, sizeof(di)); + di.file2 = templ->srcfile; + di.file = CPrep_BrowserCurrentFile(); + di.sourceoffset = templ->startoffset; + + CTemplTool_PushInstance(&stack, NULL, inst->object); + CTemplTool_MergeArgNames(TYPE_FUNC(templ->tfunc->type), TYPE_FUNC(inst->object->type)); + + nspace = CTemplTool_SetupTemplateArgumentNameSpace(templ->params, inst->args, 0); + nspace->parent = inst->object->nspace; + inst->object->nspace = nspace; + + CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace); + CFunc_ParseFuncDef(inst->object, &di, NULL, 0, 0, nspace); + CTemplTool_RemoveOuterTemplateArgumentNameSpace(nspace); + + inst->object->nspace = nspace->parent; + + CTemplTool_PopInstance(&stack); + + CPrep_StreamRemove(&templ->stream, &streamState); + copts.filesyminfo = saveDebugInfo; + + if (di.file->recordbrowseinfo) + CBrowse_NewFunction(inst->object, di.file, di.file2, di.sourceoffset, templ->endoffset); + + return 1; +} + +void CTempl_InstantiateMember(TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb, Object *object, Boolean flag) { + Boolean saveDebugInfo; + NameSpace *nspace; + Boolean saveSourceLoc; + + DeclInfo di; + CScopeSave savedScope; + TemplStack stack; + SInt32 savedState; + + if (!flag && copts.no_implicit_templates) + return; + + CTemplTool_PushInstance(&stack, NULL, object); + nspace = CTemplTool_InsertTemplateArgumentNameSpace( + tmemb->params ? tmemb->params : templ->templ__params, inst, &savedScope); + CPrep_StreamInsert(&tmemb->stream, &savedState); + + saveSourceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + symdecltoken.tokenoffset = tmemb->startoffset; + tk = lex(); + + symdecltoken = *CPrep_CurStreamElement(); + + saveDebugInfo = copts.filesyminfo; + if (copts.filesyminfo) { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, &symdecltoken); + symdecloffset = cparser_fileoffset.tokenline; + } + + if (object->sclass != TK_STATIC) + object->qual |= Q_WEAK; + + memclrw(&di, sizeof(di)); + di.file2 = tmemb->srcfile; + di.file = CPrep_BrowserCurrentFile(); + di.sourceoffset = tmemb->startoffset; + + switch (object->datatype) { + case DFUNC: + case DVFUNC: + CTemplTool_MergeArgNames(TYPE_FUNC(tmemb->object->type), TYPE_FUNC(object->type)); + CFunc_ParseFuncDef(object, &di, TYPE_CLASS(inst), 0, 0, NULL); + break; + + case DDATA: + CDecl_CompleteType(object->type); + CInit_InitializeData(object); + break; + + default: + CError_FATAL(2227); + } + + CTemplTool_PopInstance(&stack); + CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope); + CPrep_StreamRemove(&tmemb->stream, &savedState); + copts.filesyminfo = saveDebugInfo; + gForceSourceLoc = saveSourceLoc; +} + +static Boolean CTempl_GenMemberInstance(TemplClassInst *inst, ObjectTemplated *objtempl, Boolean flag) { + TemplateMember *member; + Object *parent = objtempl->parent; + + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) { + if (member->object == parent) { + CTempl_InstantiateMember(inst->templ, inst, member, OBJECT(objtempl), flag); + return 1; + } + } + + if (flag) + CError_Warning(CErrorStr233, objtempl); + return 0; +} + +static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag) { + Object *object; + Boolean result; + CScopeObjectIterator iter; + + result = 0; + + if (!flag && copts.no_implicit_templates) + return 0; + if (!flag && inst->is_extern) + return 0; + + CScope_InitObjectIterator(&iter, inst->theclass.nspace); + while ((object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) { + if (IS_TYPE_FUNC(object->type) && object->datatype != DALIAS) { + if ( + (flag || (object->flags & OBJECT_FLAGS_2)) && + !(TYPE_FUNC(object->type)->flags & (FUNC_DEFINED | FUNC_AUTO_GENERATED)) && + CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) && + (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + result = 1; + } else { + if ( + !inst->static_instantiated && + object->datatype == DDATA && + !(object->qual & Q_INLINE_DATA) && + !(object->flags & OBJECT_DEFINED) && + CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) + ) + result = 1; + } + } + + inst->static_instantiated = 1; + return result; +} + +Boolean CTempl_Instantiate(void) { + Boolean result = 0; + TemplClass *templ; + TemplClassInst *inst; + TemplPartialSpec *pspec; + TemplFuncInstance *instf; + TemplateFunction *templf; + + for (templ = ctempl_templates; templ; templ = templ->next) { + for (inst = templ->instances; inst; inst = inst->next) { + if ( + (inst->theclass.flags & CLASS_IS_TEMPL_INST) && + !inst->is_specialized && + CTempl_GenClassInstance(inst, 0) + ) + result = 1; + } + + for (pspec = templ->pspecs; pspec; pspec = pspec->next) { + for (inst = pspec->templ->instances; inst; inst = inst->next) { + if ( + (inst->theclass.flags & CLASS_IS_TEMPL_INST) && + !inst->is_specialized && + CTempl_GenClassInstance(inst, 0) + ) + result = 1; + } + } + } + + for (templf = ctempl_templatefuncs; templf; templf = templf->next) { + for (instf = templf->instances; instf; instf = instf->next) { + if ( + !instf->is_instantiated && + !instf->is_specialized && + (instf->object->flags & OBJECT_FLAGS_2) && + !(TYPE_FUNC(instf->object->type)->flags & FUNC_DEFINED) + ) + { + instf->is_instantiated = 1; + if (CTempl_GenFuncInstance(templf, instf, 0)) + result = 1; + } + } + } + + return result; +} + +Boolean CTempl_InlineFunctionCheck(Object *funcobj) { + TemplClassInst *inst; + TemplateMember *member; + Object *parent; + + CError_ASSERT(2422, IS_TYPE_FUNC(funcobj->type) && (funcobj->qual & Q_IS_TEMPLATED)); + + if (!(TYPE_FUNC(funcobj->type)->flags & FUNC_DEFINED)) { + inst = TEMPL_CLASS_INST(TYPE_METHOD(funcobj->type)->theclass); + if (!inst->is_specialized) { + parent = OBJECT_TEMPL(funcobj)->parent; + if (parent->qual & Q_INLINE) { + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) { + funcobj->qual |= Q_INLINE; + if (member->object == parent) { + CTemplTool_MergeArgNames(TYPE_FUNC(member->object->type), TYPE_FUNC(funcobj->type)); + CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(inst), &member->fileoffset, &member->stream, 0); + return 1; + } + } + } + } + } + + return 0; +} |