mirror of https://git.wuffs.org/MWCC
1882 lines
56 KiB
C
1882 lines
56 KiB
C
#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;
|
|
TokenStream 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;
|
|
}
|