#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) { CScopeParseResult pr; if ( (tk != TK_IDENTIFIER && tk != TK_COLON_COLON) || !CScope_ParseDeclName(&pr) || !pr.x8 ) { CError_Error(CErrorStr121); tk = lex(); return NULL; } if (IS_TEMPL_CLASS(pr.x8)) { if (params && !CTemplTool_EqualParams(params->data.templparam.plist, TEMPL_CLASS(pr.x8)->templ__params, 0)) { CError_Error(CErrorStr235); tk = lex(); return NULL; } } else { if (!CTemplTool_IsTemplateArgumentDependentType(pr.x8)) CError_Error(CErrorStr146); } tk = lex(); return pr.x8; } static UInt8 CTempl_GetTemplateNestIndex(NameSpace *nspace) { UInt8 count = 0; while (nspace) { if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_900)) count++; nspace = nspace->parent; } return count; } static TemplParam *CTempl_ParseParam(NameSpace *nspace, TemplParam *paramList, int index, UInt8 nindex) { TemplParam *param; DeclInfo di; short startToken; SInt32 savedState; 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; int 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; int 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_FLAGS_METHOD); return NULL; } static void CTempl_ParseMember(TemplParam *params, TemplClass *templ, DeclInfo *di, SInt32 *startOffset) { Object *object; NameSpaceObjectList *nsol; TStream stream; CPrepFileInfo *file; SInt32 offset; Boolean saveForceLoc; TemplateMember *member; if (templ->theclass.flags & CLASS_FLAGS_100) 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_FLAGS_2) && (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100000) || object->u.func.u.templ->instances) ) CError_Error(CErrorStr333, object); TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_800000 | FUNC_FLAGS_2; 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_FLAGS_100)) { 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_80000; object->sclass = di->storageclass; TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_100000; 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_FLAGS_2) CError_Error(CErrorStr333, object); TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_2 | FUNC_FLAGS_800000; 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_FLAGS_40) || (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 |= CLASS_FLAGS_40; 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_FLAGS_40) { di.thetype = tfunc->functype; di.qual |= tfunc->qual; di.nspace = di.x10->nspace; di.name = di.x10->name; } else if (tfunc->flags & FUNC_FLAGS_1000) { 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_OVERLOAD | 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_FLAGS_20) CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); TYPE_FUNC(di.thetype)->flags |= FUNC_FLAGS_1000; 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_FLAGS_20) CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); TYPE_FUNC(di.thetype)->flags |= FUNC_FLAGS_1000; 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_FLAGS_2000; 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_FLAGS_2) && !(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_2; break; case TK_UNION: mode = CLASS_MODE_1; break; case TK_STRUCT: mode = CLASS_MODE_0; 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_400000) { 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.isGeneratingDebugInfo; if (copts.nosyminline || !templ->deftoken.tokenfile) copts.isGeneratingDebugInfo = 0; CError_ASSERT(2112, (tk = lex()) == '{' || tk == ':' || tk == TK_TRY); symdecltoken = *CPrep_CurStreamElement(); if (copts.isGeneratingDebugInfo) { CPrep_NewFileOffsetInfo(&cparser_fileoffset, &templ->deftoken); symdecloffset = cparser_fileoffset.tokenline; } if (inst->object->sclass != TK_STATIC) inst->object->qual |= Q_OVERLOAD; memclrw(&di, sizeof(di)); di.file2 = templ->srcfile; di.file = CPrep_BrowserCurrentFile(); di.x60 = 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.isGeneratingDebugInfo = saveDebugInfo; if (di.file->recordbrowseinfo) CBrowse_NewFunction(inst->object, di.file, di.file2, di.x60, 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.isGeneratingDebugInfo; if (copts.isGeneratingDebugInfo) { CPrep_NewFileOffsetInfo(&cparser_fileoffset, &symdecltoken); symdecloffset = cparser_fileoffset.tokenline; } if (object->sclass != TK_STATIC) object->qual |= Q_OVERLOAD; memclrw(&di, sizeof(di)); di.file2 = tmemb->srcfile; di.file = CPrep_BrowserCurrentFile(); di.x60 = 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.isGeneratingDebugInfo = 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_FLAGS_2 | FUNC_FLAGS_100)) && CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) && (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_2) ) result = 1; } else { if ( !inst->x49 && object->datatype == DDATA && !(object->qual & Q_10000) && !(object->flags & OBJECT_FLAGS_4) && CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) ) result = 1; } } inst->x49 = 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_FLAGS_800) && !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_FLAGS_800) && !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_FLAGS_2) ) { 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_400000)); if (!(TYPE_FUNC(funcobj->type)->flags & FUNC_FLAGS_2)) { 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; }