mirror of https://git.wuffs.org/MWCC
1384 lines
45 KiB
C
1384 lines
45 KiB
C
#include "compiler/CTemplateFunc.h"
|
|
#include "compiler/CABI.h"
|
|
#include "compiler/CDecl.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CInline.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CTemplateTools.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/templates.h"
|
|
#include "compiler/types.h"
|
|
|
|
static Boolean ctempl_conversion_deduction;
|
|
static UInt8 ctempl_explicitargs_nindex;
|
|
static int ctempl_explicitargs_num;
|
|
static Boolean ctempl_explicitargs_all;
|
|
|
|
// forward decls
|
|
static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag);
|
|
static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag);
|
|
|
|
static void CTemplFunc_SetupTypeDeduce(TypeDeduce *deduce, TemplateFunction *templ, TemplArg *args) {
|
|
memclrw(deduce, sizeof(TypeDeduce));
|
|
if (templ->tfunc->nspace->theclass && (templ->tfunc->nspace->theclass->flags & CLASS_FLAGS_100))
|
|
deduce->tmclass = TEMPL_CLASS(templ->tfunc->nspace->theclass);
|
|
deduce->params = templ->params;
|
|
deduce->args = args;
|
|
}
|
|
|
|
Boolean CTempl_CanDeduceFunc(Object *object, TypeFunc *tfunc, TemplArg *args) {
|
|
DeduceInfo info;
|
|
int i;
|
|
|
|
if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object)->params, args, 0)) {
|
|
if (CTempl_DeduceType(object->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) {
|
|
for (i = 0; i < info.maxCount; i++) {
|
|
if (!info.args[i].is_deduced)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static TemplFuncInstance *CTempl_GetCreateFuncInstance(Object *funcobj, TemplArg *args, Object *object2) {
|
|
TemplFuncInstance *inst;
|
|
TemplateFunction *templ;
|
|
Object *instobj;
|
|
TemplParam *param;
|
|
TemplArg *arg;
|
|
TemplArg *last;
|
|
short paramCount;
|
|
short i;
|
|
TypeDeduce deduce;
|
|
|
|
templ = CTemplTool_GetFuncTempl(funcobj);
|
|
|
|
paramCount = 0;
|
|
param = templ->params;
|
|
while (param) {
|
|
param = param->next;
|
|
paramCount++;
|
|
}
|
|
|
|
for (i = 1, arg = args; i < paramCount; i++, arg++)
|
|
arg->next = arg + 1;
|
|
arg->next = NULL;
|
|
|
|
for (inst = templ->instances; inst; inst = inst->next) {
|
|
if (CTemplTool_EqualArgs(inst->args, args)) {
|
|
if (object2)
|
|
inst->object = object2;
|
|
return inst;
|
|
}
|
|
}
|
|
|
|
inst = galloc(sizeof(TemplFuncInstance));
|
|
memclrw(inst, sizeof(TemplFuncInstance));
|
|
|
|
for (i = 0, arg = NULL; i < paramCount; i++) {
|
|
if (arg) {
|
|
last->next = galloc(sizeof(TemplArg));
|
|
last = last->next;
|
|
} else {
|
|
last = galloc(sizeof(TemplArg));
|
|
arg = last;
|
|
}
|
|
|
|
*last = *args;
|
|
last->next = NULL;
|
|
args++;
|
|
|
|
if (last->pid.type == TPT_NONTYPE) {
|
|
CError_ASSERT(114, last->data.paramdecl.expr);
|
|
last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1);
|
|
}
|
|
}
|
|
|
|
inst->args = arg;
|
|
inst->next = templ->instances;
|
|
templ->instances = inst;
|
|
|
|
if (!object2) {
|
|
instobj = CParser_NewFunctionObject(NULL);
|
|
instobj->access = funcobj->access;
|
|
instobj->nspace = funcobj->nspace;
|
|
instobj->sclass = funcobj->sclass;
|
|
instobj->qual = funcobj->qual | Q_80000;
|
|
instobj->name = templ->name;
|
|
instobj->u.func.inst = inst;
|
|
|
|
CTemplFunc_SetupTypeDeduce(&deduce, templ, inst->args);
|
|
if (funcobj->nspace->theclass && (funcobj->nspace->theclass->flags & CLASS_FLAGS_800)) {
|
|
deduce.tmclass = TEMPL_CLASS_INST(funcobj->nspace->theclass)->templ;
|
|
deduce.inst = TEMPL_CLASS_INST(funcobj->nspace->theclass);
|
|
}
|
|
|
|
instobj->type = CTemplTool_DeduceTypeCopy(&deduce, funcobj->type, &instobj->qual);
|
|
inst->object = instobj;
|
|
|
|
if (IS_TYPE_FUNC(instobj->type)) {
|
|
TYPE_FUNC(instobj->type)->flags &= ~FUNC_FLAGS_2;
|
|
if (TYPE_FUNC(instobj->type)->flags & FUNC_FLAGS_1000) {
|
|
FuncArg *funcarg;
|
|
CError_ASSERT(152, TYPE_FUNC(instobj->type)->flags & FUNC_FLAGS_METHOD);
|
|
CError_ASSERT(153, funcarg = TYPE_FUNC(instobj->type)->args);
|
|
|
|
if (TYPE_METHOD(instobj->type)->theclass->flags & CLASS_FLAGS_20)
|
|
CError_ASSERT(156, funcarg = funcarg->next);
|
|
|
|
if (funcarg->next)
|
|
CDecl_CheckCtorIntegrity(funcarg->next, TYPE_METHOD(instobj->type)->theclass);
|
|
}
|
|
}
|
|
|
|
if ((instobj->qual & Q_INLINE) && templ->stream.tokens)
|
|
CInline_AddTemplateFunctionAction(instobj, templ, inst);
|
|
|
|
} else {
|
|
inst->object = object2;
|
|
}
|
|
|
|
return inst;
|
|
}
|
|
|
|
TemplFuncInstance *CTempl_CheckFuncInstance(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2) {
|
|
DeduceInfo info;
|
|
int i;
|
|
|
|
if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object1)->params, args, 1))
|
|
return NULL;
|
|
|
|
if (!CTempl_DeduceType(object1->type, 0, TYPE(tfunc), 0, info.args, 0, 0))
|
|
return NULL;
|
|
|
|
i = 0;
|
|
while (i < info.maxCount) {
|
|
if (!info.args[i++].is_deduced)
|
|
return NULL;
|
|
}
|
|
|
|
return CTempl_GetCreateFuncInstance(object1, info.args, object2);
|
|
}
|
|
|
|
TemplFuncInstance *CTempl_DeduceFunc(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2, Boolean flag) {
|
|
return CTempl_CheckFuncInstance(object1, tfunc, args, object2);
|
|
}
|
|
|
|
static Boolean CTempl_FuncIsAtLeastAsSpecialized(Object *func1, Object *func2) {
|
|
int i;
|
|
FuncArg *arg1;
|
|
FuncArg *arg2;
|
|
Type *type1;
|
|
Type *type2;
|
|
UInt32 qual1;
|
|
UInt32 qual2;
|
|
DeduceInfo info;
|
|
|
|
arg1 = TYPE_FUNC(func2->type)->args;
|
|
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type)))
|
|
arg1 = arg1->next;
|
|
|
|
i = 0;
|
|
while (1) {
|
|
if (!arg1)
|
|
break;
|
|
CError_ASSERT(231, arg1->type != &stvoid);
|
|
if (arg1 == &elipsis)
|
|
break;
|
|
if (arg1 == &oldstyle)
|
|
break;
|
|
arg1 = arg1->next;
|
|
i++;
|
|
}
|
|
|
|
if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(func2)->params, NULL, 0))
|
|
return 0;
|
|
|
|
arg1 = TYPE_FUNC(func1->type)->args;
|
|
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func1->type)))
|
|
arg1 = arg1->next;
|
|
|
|
arg2 = TYPE_FUNC(func2->type)->args;
|
|
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type)))
|
|
arg2 = arg2->next;
|
|
|
|
while (i > 0) {
|
|
if (!arg1)
|
|
break;
|
|
if (arg1 == &elipsis)
|
|
break;
|
|
if (arg1 == &oldstyle)
|
|
break;
|
|
|
|
CError_ASSERT(255, arg2);
|
|
|
|
type1 = arg1->type;
|
|
qual1 = arg1->qual & (Q_CONST | Q_VOLATILE);
|
|
qual2 = arg2->qual & (Q_CONST | Q_VOLATILE);
|
|
type2 = arg2->type;
|
|
|
|
if (!CTemplTool_IsTemplateArgumentDependentType(type2)) {
|
|
if (IS_TYPE_REFERENCE(type1))
|
|
type1 = TPTR_TARGET(type1);
|
|
type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
|
|
|
|
if (IS_TYPE_REFERENCE(type2))
|
|
type2 = TPTR_TARGET(type2);
|
|
type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
|
|
|
|
if (!is_typesame(type1, type2) || qual1 != qual2)
|
|
return 0;
|
|
} else {
|
|
if (!CTempl_DeduceType(type2, qual2, type1, qual1, info.args, 0, 0))
|
|
return 0;
|
|
}
|
|
|
|
arg1 = arg1->next;
|
|
arg2 = arg2->next;
|
|
i--;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
Boolean CTempl_FuncIsMoreSpecialized(Object *object1, Object *object2) {
|
|
return CTempl_FuncIsAtLeastAsSpecialized(object1, object2) && !CTempl_FuncIsAtLeastAsSpecialized(object2, object1);
|
|
}
|
|
|
|
Object *CTempl_PartialOrdering(Object *object, ObjectList *list, int count) {
|
|
int i;
|
|
int j;
|
|
Object **array;
|
|
ObjectList *scan;
|
|
Object *arrayBuffer[16];
|
|
|
|
for (count = 1, scan = list; scan; scan = scan->next) {
|
|
if (IS_TEMPL_FUNC(scan->object->type))
|
|
count++;
|
|
}
|
|
|
|
if (count > 16)
|
|
array = lalloc(sizeof(Object *) * count);
|
|
else
|
|
array = arrayBuffer;
|
|
|
|
array[0] = object;
|
|
for (i = 1, scan = list; scan; scan = scan->next) {
|
|
if (IS_TEMPL_FUNC(scan->object->type))
|
|
array[i++] = scan->object;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (array[i]) {
|
|
for (j = 0; j < count; j++) {
|
|
if (array[j] && i != j && CTempl_FuncIsMoreSpecialized(array[i], array[j]))
|
|
array[j] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
object = NULL;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (array[i]) {
|
|
if (object)
|
|
return NULL;
|
|
object = array[i];
|
|
}
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
int CTempl_GetTemplateArgumentExpressionIndex(TemplArg *arg) {
|
|
CError_ASSERT(529, arg->data.paramdecl.expr);
|
|
|
|
if (ENODE_IS(arg->data.paramdecl.expr, ETEMPLDEP) && arg->data.paramdecl.expr->data.templdep.subtype == TDE_PARAM)
|
|
return arg->data.paramdecl.expr->data.templdep.u.pid.index;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static Type *CTempl_GetSpecifiedType(TemplateFunction *templ, Type *type, UInt32 qual, TemplArg *args, UInt32 *resultQual) {
|
|
TypeDeduce deduce;
|
|
|
|
CTemplFunc_SetupTypeDeduce(&deduce, templ, args);
|
|
*resultQual = qual;
|
|
return CTemplTool_DeduceTypeCopy(&deduce, type, resultQual);
|
|
}
|
|
|
|
static Boolean CTempl_DeduceTemplateArgs(TemplArg *args1, TemplArg *args2, TemplArg *argArray) {
|
|
int index;
|
|
|
|
while (1) {
|
|
if (!args1)
|
|
return !args2;
|
|
if (!args2)
|
|
return 0;
|
|
|
|
if (args1->pid.type != args2->pid.type)
|
|
return 0;
|
|
|
|
switch (args1->pid.type) {
|
|
case TPT_TYPE:
|
|
if (!CTempl_DeduceType1(
|
|
args1->data.typeparam.type, args1->data.typeparam.qual,
|
|
args2->data.typeparam.type, args2->data.typeparam.qual,
|
|
argArray, 1
|
|
))
|
|
return 0;
|
|
break;
|
|
|
|
case TPT_NONTYPE:
|
|
if (CTemplTool_IsTemplateArgumentDependentExpression(args1->data.paramdecl.expr)) {
|
|
index = CTempl_GetTemplateArgumentExpressionIndex(args1);
|
|
if (index < 0)
|
|
return 1;
|
|
|
|
if (argArray[index].is_deduced) {
|
|
if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, argArray[index].data.paramdecl.expr))
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.paramdecl.expr = args2->data.paramdecl.expr;
|
|
argArray[index].pid.type = TPT_NONTYPE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
} else {
|
|
if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, args1->data.paramdecl.expr))
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case TPT_TEMPLATE:
|
|
if (!IS_TEMPL_CLASS(args2->data.ttargtype))
|
|
return 0;
|
|
|
|
index = args1->pid.index;
|
|
if (argArray[index].is_deduced) {
|
|
if (args2->data.ttargtype != argArray[index].data.ttargtype)
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.ttargtype = args2->data.ttargtype;
|
|
argArray[index].pid.type = TPT_TEMPLATE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CError_FATAL(640);
|
|
}
|
|
|
|
args1 = args1->next;
|
|
args2 = args2->next;
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceTemplDepTemplate(TemplClass *templ1, TemplArg *args1, TemplClass *templ2, TemplArg *args2, TemplArg *argArray) {
|
|
if (templ1 != templ2)
|
|
return 0;
|
|
|
|
return CTempl_DeduceTemplateArgs(args2, args1, argArray);
|
|
}
|
|
|
|
static Boolean CTempl_DeduceTemplateType(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray) {
|
|
TemplClassInst *scan;
|
|
|
|
for (scan = templ->instances; scan; scan = scan->next) {
|
|
if (scan == inst)
|
|
return CTempl_DeduceTemplateArgs(args, scan->oargs ? scan->oargs : scan->inst_args, argArray);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean CTempl_DeduceTemplateTypeBase(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray, Boolean flag) {
|
|
ClassList *base;
|
|
|
|
if (CTempl_DeduceTemplateType(templ, args, inst, argArray))
|
|
return 1;
|
|
|
|
if (flag) {
|
|
for (base = inst->theclass.bases; base; base = base->next) {
|
|
if (CTempl_DeduceTemplateType(templ, args, TEMPL_CLASS_INST(base->base), argArray)) {
|
|
ctempl_conversion_deduction = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (base = inst->theclass.bases; base; base = base->next) {
|
|
if (CTempl_DeduceTemplateTypeBase(templ, args, TEMPL_CLASS_INST(base->base), argArray, 1)) {
|
|
ctempl_conversion_deduction = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean CTempl_DeduceQualTemplate(TypeTemplDep *type1, TemplArg *args1, Type *type2, TemplArg *argArray) {
|
|
int index;
|
|
|
|
if (type1->dtype == TEMPLDEP_ARGUMENT && type1->u.pid.type == TPT_TEMPLATE) {
|
|
index = type1->u.pid.index;
|
|
if (IS_TEMPL_CLASS_INST(type2)) {
|
|
if (argArray[index].is_deduced) {
|
|
if (argArray[index].data.ttargtype != TYPE(TEMPL_CLASS_INST(type2)->templ))
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.ttargtype = TYPE(TEMPL_CLASS_INST(type2)->templ);
|
|
argArray[index].pid.type = TPT_TEMPLATE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
|
|
return CTempl_DeduceTemplateArgs(args1, TEMPL_CLASS_INST(type2)->inst_args, argArray);
|
|
}
|
|
|
|
if (IS_TYPE_TEMPLATE(type2)) {
|
|
if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) {
|
|
if (argArray[index].is_deduced) {
|
|
if (argArray[index].data.ttargtype != TYPE(TYPE_TEMPLATE(type2)->u.templ.templ))
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.ttargtype = TYPE(TYPE_TEMPLATE(type2)->u.templ.templ);
|
|
argArray[index].pid.type = TPT_TEMPLATE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
|
|
return CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.templ.args, argArray);
|
|
}
|
|
|
|
if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_QUALTEMPL) {
|
|
return
|
|
CTempl_DeduceTypeTemplDep(type1, 0, TYPE(TYPE_TEMPLATE(type2)->u.qualtempl.type), 0, argArray, 1) &&
|
|
CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.qualtempl.args, argArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) {
|
|
Type *tmptype;
|
|
UInt32 tmpqual;
|
|
short index;
|
|
Boolean f;
|
|
UInt32 modqual;
|
|
|
|
switch (type1->dtype) {
|
|
case TEMPLDEP_ARGUMENT:
|
|
index = type1->u.pid.index;
|
|
tmptype = type2;
|
|
if (type1->u.pid.type == TPT_TEMPLATE) {
|
|
if (argArray[index].is_deduced) {
|
|
if (!is_typesame(tmptype, argArray[index].data.ttargtype))
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.ttargtype = type2;
|
|
argArray[index].pid.type = TPT_TEMPLATE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
switch (type2->type) {
|
|
case TYPEPOINTER:
|
|
tmpqual = qual2;
|
|
f = 0;
|
|
qual2 = TPTR_QUAL(type2);
|
|
modqual = qual2;
|
|
|
|
if ((modqual & Q_CONST) && (qual1 & Q_CONST)) {
|
|
modqual &= ~Q_CONST;
|
|
f = 1;
|
|
}
|
|
if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) {
|
|
modqual &= ~Q_VOLATILE;
|
|
f = 1;
|
|
}
|
|
|
|
if (f) {
|
|
tmptype = galloc(sizeof(TypePointer));
|
|
*TYPE_POINTER(tmptype) = *TYPE_POINTER(type2);
|
|
TPTR_QUAL(tmptype) = modqual;
|
|
}
|
|
|
|
if (flag && (qual2 | modqual) != (qual1 | modqual))
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case TYPEMEMBERPOINTER:
|
|
tmpqual = qual2;
|
|
f = 0;
|
|
qual2 = TYPE_MEMBER_POINTER(type2)->qual;
|
|
modqual = qual2;
|
|
|
|
if ((modqual & Q_CONST) && (qual1 & Q_CONST)) {
|
|
modqual &= ~Q_CONST;
|
|
f = 1;
|
|
}
|
|
if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) {
|
|
modqual &= ~Q_VOLATILE;
|
|
f = 1;
|
|
}
|
|
|
|
if (f) {
|
|
tmptype = galloc(sizeof(TypeMemberPointer));
|
|
*TYPE_MEMBER_POINTER(tmptype) = *TYPE_MEMBER_POINTER(type2);
|
|
TYPE_MEMBER_POINTER(tmptype)->qual = modqual;
|
|
}
|
|
|
|
if (flag && (qual2 | modqual) != (qual1 | modqual))
|
|
return 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
tmpqual = 0;
|
|
if ((qual2 & Q_CONST) && !(qual1 & Q_CONST))
|
|
tmpqual |= Q_CONST;
|
|
if ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE))
|
|
tmpqual |= Q_VOLATILE;
|
|
|
|
if (flag && (qual2 | tmpqual) != (qual1 | tmpqual))
|
|
return 0;
|
|
}
|
|
|
|
if (argArray[index].is_deduced) {
|
|
if (!is_typesame(tmptype, argArray[index].data.typeparam.type) || tmpqual != argArray[index].data.typeparam.qual)
|
|
return 0;
|
|
} else {
|
|
argArray[index].data.typeparam.type = tmptype;
|
|
argArray[index].data.typeparam.qual = tmpqual;
|
|
argArray[index].pid.type = TPT_TYPE;
|
|
argArray[index].is_deduced = 1;
|
|
}
|
|
return 1;
|
|
|
|
case TEMPLDEP_QUALNAME:
|
|
return 1;
|
|
|
|
case TEMPLDEP_TEMPLATE:
|
|
if (IS_TYPE_CLASS(type2))
|
|
return CTempl_DeduceTemplateTypeBase(
|
|
type1->u.templ.templ, type1->u.templ.args,
|
|
TEMPL_CLASS_INST(type2), argArray, 0);
|
|
|
|
if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE)
|
|
return CTempl_DeduceTemplDepTemplate(
|
|
TYPE_TEMPLATE(type2)->u.templ.templ, TYPE_TEMPLATE(type2)->u.templ.args,
|
|
type1->u.templ.templ, type1->u.templ.args,
|
|
argArray
|
|
);
|
|
|
|
return 0;
|
|
|
|
case TEMPLDEP_ARRAY:
|
|
if (IS_TYPE_ARRAY(type2)) {
|
|
SInt32 elements;
|
|
|
|
if (!CTempl_DeduceType1(type1->u.array.type, qual1, TPTR_TARGET(type2), qual2, argArray, flag))
|
|
return 0;
|
|
|
|
if (ENODE_IS(type1->u.array.index, EINTCONST)) {
|
|
CError_ASSERT(961, TPTR_TARGET(type2)->size);
|
|
return (type2->size / TPTR_TARGET(type2)->size) == CInt64_GetULong(&type1->u.array.index->data.intval);
|
|
}
|
|
|
|
if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM)
|
|
return 1;
|
|
|
|
CError_ASSERT(970, TPTR_TARGET(type2)->size);
|
|
|
|
elements = type2->size / TPTR_TARGET(type2)->size;
|
|
index = type1->u.array.index->data.templdep.u.pid.index;
|
|
if (argArray[index].is_deduced) {
|
|
CError_ASSERT(976, ENODE_IS(argArray[index].data.paramdecl.expr, EINTCONST));
|
|
return elements == CInt64_GetULong(&argArray[index].data.paramdecl.expr->data.intval);
|
|
} else {
|
|
argArray[index].data.paramdecl.expr = intconstnode(CABI_GetPtrDiffTType(), elements);
|
|
argArray[index].pid.type = TPT_NONTYPE;
|
|
argArray[index].is_deduced = 1;
|
|
return 1;
|
|
}
|
|
} else if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_ARRAY) {
|
|
if (!CTempl_DeduceType1(type1->u.array.type, qual1, TYPE_TEMPLATE(type2)->u.array.type, qual2, argArray, flag))
|
|
return 0;
|
|
|
|
if (ENODE_IS(type1->u.array.index, EINTCONST)) {
|
|
return ENODE_IS(TYPE_TEMPLATE(type2)->u.array.index, EINTCONST) &&
|
|
CInt64_Equal(type1->u.array.index->data.intval, TYPE_TEMPLATE(type2)->u.array.index->data.intval);
|
|
}
|
|
|
|
if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM)
|
|
return 1;
|
|
|
|
index = type1->u.array.index->data.templdep.u.pid.index;
|
|
if (argArray[index].is_deduced) {
|
|
return CTemplTool_EqualExprTypes(TYPE_TEMPLATE(type2)->u.array.index, argArray[index].data.paramdecl.expr);
|
|
} else {
|
|
argArray[index].data.paramdecl.expr = TYPE_TEMPLATE(type2)->u.array.index;
|
|
argArray[index].pid.type = TPT_NONTYPE;
|
|
argArray[index].is_deduced = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
case TEMPLDEP_QUALTEMPL:
|
|
return CTempl_DeduceQualTemplate(type1->u.qualtempl.type, type1->u.qualtempl.args, type2, argArray);
|
|
|
|
case TEMPLDEP_BITFIELD:
|
|
default:
|
|
CError_FATAL(1022);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceFuncType(TypeFunc *tfunc1, TypeFunc *tfunc2, TemplArg *argArray) {
|
|
FuncArg *arg1;
|
|
FuncArg *arg2;
|
|
Type *type2;
|
|
Type *type1;
|
|
UInt32 qual2;
|
|
UInt32 qual1;
|
|
|
|
arg1 = tfunc1->args;
|
|
arg2 = tfunc2->args;
|
|
|
|
if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc1) && !IS_TYPEFUNC_METHOD(tfunc2)) {
|
|
CError_ASSERT(1045, arg1);
|
|
arg1 = arg1->next;
|
|
}
|
|
|
|
while (1) {
|
|
if (arg1 == NULL)
|
|
return !arg2;
|
|
if (arg1 == &oldstyle)
|
|
return arg2 == &oldstyle;
|
|
if (arg1 == &elipsis)
|
|
return arg2 == &elipsis;
|
|
|
|
if (arg2 == NULL || arg2 == &oldstyle || arg2 == &elipsis)
|
|
return 0;
|
|
|
|
qual2 = arg2->qual;
|
|
type2 = CParser_RemoveTopMostQualifiers(arg2->type, &qual2);
|
|
|
|
qual1 = arg1->qual;
|
|
type1 = CParser_RemoveTopMostQualifiers(arg1->type, &qual1);
|
|
|
|
if (!CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, 1))
|
|
return 0;
|
|
|
|
arg1 = arg1->next;
|
|
arg2 = arg2->next;
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) {
|
|
while (1) {
|
|
switch (type1->type) {
|
|
case TYPETEMPLATE:
|
|
return CTempl_DeduceTypeTemplDep(TYPE_TEMPLATE(type1), qual1, type2, qual2, argArray, flag);
|
|
|
|
case TYPEVOID:
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEENUM:
|
|
case TYPESTRUCT:
|
|
case TYPECLASS:
|
|
return type1 == type2;
|
|
|
|
case TYPEMEMBERPOINTER:
|
|
if (type1->type != type2->type || TYPE_MEMBER_POINTER(type1)->qual != TYPE_MEMBER_POINTER(type2)->qual)
|
|
return 0;
|
|
if (!CTempl_DeduceType1(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray, flag))
|
|
return 0;
|
|
type1 = TYPE_MEMBER_POINTER(type1)->ty2;
|
|
type2 = TYPE_MEMBER_POINTER(type2)->ty2;
|
|
continue;
|
|
|
|
case TYPEARRAY:
|
|
if (type2->type != TYPEARRAY)
|
|
return 0;
|
|
type1 = TPTR_TARGET(type1);
|
|
type2 = TPTR_TARGET(type2);
|
|
continue;
|
|
|
|
case TYPEPOINTER:
|
|
if (type2->type != TYPEPOINTER || TPTR_QUAL(type1) != TPTR_QUAL(type2))
|
|
return 0;
|
|
type1 = TPTR_TARGET(type1);
|
|
type2 = TPTR_TARGET(type2);
|
|
continue;
|
|
|
|
case TYPEFUNC:
|
|
if (type1->type != type2->type)
|
|
return 0;
|
|
|
|
if (CTempl_DeduceType1(TYPE_FUNC(type1)->functype, TYPE_FUNC(type1)->qual, TYPE_FUNC(type2)->functype, TYPE_FUNC(type2)->qual, argArray, flag))
|
|
return CTempl_DeduceFuncType(TYPE_FUNC(type1), TYPE_FUNC(type2), argArray);
|
|
|
|
return 0;
|
|
|
|
default:
|
|
CError_FATAL(1124);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceType2(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
|
|
while (1) {
|
|
switch (type1->type) {
|
|
case TYPEPOINTER:
|
|
if (type2->type != TYPEPOINTER)
|
|
return 0;
|
|
if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1)))
|
|
return 0;
|
|
type1 = TPTR_TARGET(type1);
|
|
type2 = TPTR_TARGET(type2);
|
|
continue;
|
|
|
|
case TYPEMEMBERPOINTER:
|
|
if (type2->type != TYPEMEMBERPOINTER)
|
|
return 0;
|
|
if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual))
|
|
return 0;
|
|
if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray))
|
|
return 0;
|
|
type1 = TYPE_MEMBER_POINTER(type1)->ty2;
|
|
type2 = TYPE_MEMBER_POINTER(type2)->ty2;
|
|
continue;
|
|
|
|
default:
|
|
if (CParser_IsSameOrMoreCVQualified(qual2, qual1))
|
|
return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceType3(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
|
|
Boolean flag = 0;
|
|
|
|
while (1) {
|
|
switch (type1->type) {
|
|
case TYPEPOINTER:
|
|
flag = 1;
|
|
if (type2->type != TYPEPOINTER)
|
|
return 0;
|
|
if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1)))
|
|
return 0;
|
|
type1 = TPTR_TARGET(type1);
|
|
type2 = TPTR_TARGET(type2);
|
|
continue;
|
|
|
|
case TYPEMEMBERPOINTER:
|
|
flag = 1;
|
|
if (type2->type != TYPEMEMBERPOINTER)
|
|
return 0;
|
|
if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual))
|
|
return 0;
|
|
if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray))
|
|
return 0;
|
|
type1 = TYPE_MEMBER_POINTER(type1)->ty2;
|
|
type2 = TYPE_MEMBER_POINTER(type2)->ty2;
|
|
continue;
|
|
|
|
default:
|
|
if (!flag)
|
|
return 0;
|
|
if (CParser_IsSameOrMoreCVQualified(qual2, qual1))
|
|
return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_DeduceType4(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
|
|
if (IS_TYPE_POINTER_ONLY(type1)) {
|
|
if (!IS_TYPE_POINTER_ONLY(type2))
|
|
return 0;
|
|
|
|
if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type1), TPTR_QUAL(type2)))
|
|
return 0;
|
|
|
|
type1 = TPTR_TARGET(type1);
|
|
type2 = TPTR_TARGET(type2);
|
|
}
|
|
|
|
if (IS_TYPE_TEMPLATE(type1) && TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_TEMPLATE && IS_TYPE_CLASS(type2)) {
|
|
if (CParser_IsSameOrMoreCVQualified(qual1, qual2))
|
|
return CTempl_DeduceTemplateTypeBase(
|
|
TYPE_TEMPLATE(type1)->u.templ.templ,
|
|
TYPE_TEMPLATE(type1)->u.templ.args,
|
|
TEMPL_CLASS_INST(type2),
|
|
argArray,
|
|
1);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Boolean CTempl_DeduceType(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag1, Boolean flag2) {
|
|
Boolean flag31;
|
|
Boolean flag8;
|
|
|
|
flag31 = 0;
|
|
flag8 = 1;
|
|
|
|
if (flag1 || flag2) {
|
|
if (IS_TYPE_REFERENCE(type1)) {
|
|
type1 = TPTR_TARGET(type1);
|
|
flag31 = 1;
|
|
} else {
|
|
switch (type2->type) {
|
|
case TYPEFUNC:
|
|
type2 = CDecl_NewPointerType(type2);
|
|
break;
|
|
case TYPEARRAY:
|
|
type2 = CDecl_NewPointerType(TPTR_TARGET(type2));
|
|
break;
|
|
}
|
|
|
|
type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
|
|
type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
|
|
}
|
|
flag8 = 0;
|
|
}
|
|
|
|
if (CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, flag8))
|
|
return 1;
|
|
|
|
if (flag1 || flag2) {
|
|
if (flag31 && CTempl_DeduceType2(type1, qual1, type2, qual2, argArray))
|
|
return 1;
|
|
if (CTempl_DeduceType3(type1, qual1, type2, qual2, argArray))
|
|
return 1;
|
|
if (flag1 && CTempl_DeduceType4(type1, qual1, type2, qual2, argArray))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean CTempl_TypeNeedsDeduction(Type *type) {
|
|
FuncArg *arg;
|
|
Boolean result;
|
|
|
|
while (1) {
|
|
switch (type->type) {
|
|
case TYPETEMPLATE:
|
|
switch (TYPE_TEMPLATE(type)->dtype) {
|
|
case TEMPLDEP_ARGUMENT:
|
|
if (
|
|
TYPE_TEMPLATE(type)->u.pid.index >= ctempl_explicitargs_num ||
|
|
TYPE_TEMPLATE(type)->u.pid.nindex != ctempl_explicitargs_nindex
|
|
)
|
|
ctempl_explicitargs_all = 0;
|
|
return 1;
|
|
|
|
case TEMPLDEP_QUALNAME:
|
|
CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qual.type));
|
|
return 1;
|
|
|
|
case TEMPLDEP_TEMPLATE:
|
|
ctempl_explicitargs_all = 0;
|
|
return 1;
|
|
|
|
case TEMPLDEP_ARRAY:
|
|
CTempl_TypeNeedsDeduction(TYPE_TEMPLATE(type)->u.array.type);
|
|
ctempl_explicitargs_all = 0;
|
|
return 1;
|
|
|
|
case TEMPLDEP_QUALTEMPL:
|
|
CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qualtempl.type));
|
|
ctempl_explicitargs_all = 0;
|
|
return 1;
|
|
|
|
case TEMPLDEP_BITFIELD:
|
|
default:
|
|
CError_FATAL(1357);
|
|
}
|
|
|
|
case TYPEVOID:
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEENUM:
|
|
case TYPESTRUCT:
|
|
case TYPECLASS:
|
|
return 0;
|
|
|
|
case TYPEMEMBERPOINTER:
|
|
result = 0;
|
|
if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty1))
|
|
result = 1;
|
|
if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty2))
|
|
result = 1;
|
|
return result;
|
|
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
type = TPTR_TARGET(type);
|
|
continue;
|
|
|
|
case TYPEFUNC:
|
|
result = 0;
|
|
for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis; arg = arg->next) {
|
|
if (CTempl_TypeNeedsDeduction(arg->type))
|
|
result = 1;
|
|
}
|
|
|
|
if (CTempl_TypeNeedsDeduction(TYPE_FUNC(type)->functype))
|
|
result = 1;
|
|
return result;
|
|
|
|
default:
|
|
CError_FATAL(1389);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Boolean CTempl_MatchTemplFunc(Object *object, DeduceInfo *info, FuncArg *args, ENodeList *exprs, Match13 *match13ptr) {
|
|
Match13 match13;
|
|
int i;
|
|
|
|
memclrw(&match13, sizeof(match13));
|
|
|
|
while (1) {
|
|
if (!args || args->type == &stvoid) {
|
|
if (!exprs)
|
|
break;
|
|
return 0;
|
|
}
|
|
|
|
if (args == &elipsis)
|
|
break;
|
|
if (args == &oldstyle)
|
|
break;
|
|
|
|
if (!exprs) {
|
|
if (args->dexpr)
|
|
break;
|
|
return 0;
|
|
}
|
|
|
|
ctempl_explicitargs_nindex = info->x12C;
|
|
ctempl_explicitargs_num = info->count;
|
|
ctempl_explicitargs_all = 1;
|
|
|
|
if (CTempl_TypeNeedsDeduction(args->type)) {
|
|
if (!ctempl_explicitargs_all) {
|
|
UInt32 cv2;
|
|
UInt32 cv1;
|
|
Type *type2;
|
|
Type *type1;
|
|
UInt32 qual2;
|
|
UInt32 qual1;
|
|
|
|
type1 = args->type;
|
|
qual1 = args->qual & (Q_CONST | Q_VOLATILE);
|
|
|
|
type2 = exprs->node->rtype;
|
|
qual2 = ENODE_QUALS(exprs->node);
|
|
|
|
if (IS_TYPE_REFERENCE(type1)) {
|
|
type1 = TPTR_TARGET(type1);
|
|
cv1 = CParser_GetCVTypeQualifiers(type1, qual1);
|
|
cv2 = CParser_GetCVTypeQualifiers(type2, qual2);
|
|
if (
|
|
(!(cv1 & Q_CONST) && (cv2 & Q_CONST)) ||
|
|
(!(cv1 & Q_VOLATILE) && (cv2 & Q_VOLATILE))
|
|
)
|
|
return 0;
|
|
|
|
if (!(cv1 & Q_CONST) && !CExpr_IsLValue(exprs->node))
|
|
return 0;
|
|
}
|
|
|
|
type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
|
|
type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
|
|
|
|
if (ENODE_IS(exprs->node, EOBJREF) && IS_TEMPL_FUNC(exprs->node->data.objref->type))
|
|
return 0;
|
|
|
|
if (ENODE_IS(exprs->node, EOBJLIST)) {
|
|
NameSpaceObjectList *list;
|
|
|
|
for (list = exprs->node->data.objlist.list; list; list = list->next) {
|
|
if (list->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(list->object)->type))
|
|
break;
|
|
}
|
|
|
|
if (list)
|
|
return 0;
|
|
|
|
if (IS_TYPE_FUNC(type2))
|
|
type2 = CDecl_NewPointerType(type2);
|
|
}
|
|
|
|
ctempl_conversion_deduction = 0;
|
|
if (!CTempl_DeduceType(type1, qual1, type2, qual2, info->args, 1, 0))
|
|
return 0;
|
|
|
|
if (ctempl_conversion_deduction)
|
|
match13.anotherm5.x4++;
|
|
else
|
|
match13.anotherm5.x0++;
|
|
|
|
if (IS_TYPE_POINTER_ONLY(args->type))
|
|
CExpr_MatchCV(type2, qual2, args->type, args->qual, &match13);
|
|
|
|
} else {
|
|
Type *type;
|
|
UInt32 qual;
|
|
|
|
type = CTempl_GetSpecifiedType(CTemplTool_GetFuncTempl(object), args->type, args->qual, info->args, &qual);
|
|
if (type && !CExpr_MatchAssign(type, qual, exprs->node, &match13))
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (copts.old_argmatch && !CExpr_MatchAssign(args->type, args->qual, exprs->node, &match13))
|
|
return 0;
|
|
}
|
|
|
|
exprs = exprs->next;
|
|
args = args->next;
|
|
}
|
|
|
|
for (i = 0; i < info->maxCount; i++) {
|
|
if (!info->args[i].is_deduced)
|
|
return 0;
|
|
info->args[i].next = &info->args[i + 1];
|
|
}
|
|
info->args[info->maxCount].next = NULL;
|
|
|
|
return CExpr_MatchCompare(object, match13ptr, &match13);
|
|
}
|
|
|
|
void CTempl_FuncMatch(NameSpaceObjectList *list, TemplArg *args, ENodeList *argexprs, Match13 *match13ptr, ENode *expr) {
|
|
Object *obj;
|
|
Object *success;
|
|
Object *object1;
|
|
FuncMatchArgs funcMatchArgs;
|
|
DeduceInfo info;
|
|
DeduceInfo info2;
|
|
|
|
object1 = match13ptr->obj;
|
|
success = NULL;
|
|
while (list) {
|
|
obj = OBJECT(list->object);
|
|
if (
|
|
obj->otype == OT_OBJECT &&
|
|
IS_TEMPL_FUNC(obj->type) &&
|
|
CExpr_GetFuncMatchArgs(obj, argexprs, expr, &funcMatchArgs) &&
|
|
CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(obj)->params, args, 0) &&
|
|
CTempl_MatchTemplFunc(obj, &info, funcMatchArgs.args, funcMatchArgs.exprs, match13ptr)
|
|
)
|
|
{
|
|
info2 = info;
|
|
if (info.args == info.argBuffer)
|
|
info2.args = info2.argBuffer;
|
|
success = obj;
|
|
}
|
|
list = list->next;
|
|
}
|
|
|
|
if (success) {
|
|
if (match13ptr->list) {
|
|
ENodeList *argexpr = argexprs;
|
|
int argexprcount = 0;
|
|
while (argexpr) {
|
|
argexpr = argexpr->next;
|
|
argexprcount++;
|
|
}
|
|
|
|
obj = CTempl_PartialOrdering(match13ptr->obj, match13ptr->list, argexprcount);
|
|
if (!obj) {
|
|
CError_OverloadedFunctionError(match13ptr->obj, match13ptr->list);
|
|
match13ptr->list = NULL;
|
|
if (object1)
|
|
match13ptr->obj = object1;
|
|
else
|
|
match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object;
|
|
} else {
|
|
NameSpaceObjectList mylist;
|
|
mylist.next = NULL;
|
|
mylist.object = OBJ_BASE(obj);
|
|
memclrw(match13ptr, sizeof(Match13));
|
|
CTempl_FuncMatch(&mylist, args, argexprs, match13ptr, expr);
|
|
}
|
|
} else {
|
|
match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object;
|
|
}
|
|
} else {
|
|
match13ptr->obj = object1;
|
|
}
|
|
}
|
|
|
|
static Boolean CExpr_DeduceFromObjList(FuncArg *arg, NameSpaceObjectList *list, DeduceInfo *info) {
|
|
TemplArg *savebuf;
|
|
NameSpaceObjectList *scan;
|
|
SInt32 size;
|
|
|
|
for (scan = list; scan; scan = scan->next) {
|
|
if (scan->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(scan->object)->type))
|
|
return 0;
|
|
}
|
|
|
|
size = sizeof(TemplArg) * info->maxCount;
|
|
savebuf = lalloc(size);
|
|
|
|
for (scan = list; scan; scan = scan->next) {
|
|
if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) {
|
|
Object *obj;
|
|
|
|
memcpy(savebuf, info->args, size);
|
|
|
|
obj = OBJECT(scan->object);
|
|
if (CTempl_DeduceType(
|
|
arg->type, arg->qual & (Q_CONST | Q_VOLATILE),
|
|
obj->type, obj->qual,
|
|
savebuf, 1, 0
|
|
))
|
|
{
|
|
memcpy(info->args, savebuf, size);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Object *CTempl_DeduceFromFunctionCall(Object *funcobj, TemplArg *templargs, ENodeList *argexprs) {
|
|
DeduceInfo info;
|
|
FuncArg *arg;
|
|
int i;
|
|
|
|
CError_ASSERT(1655, IS_TEMPL_FUNC(funcobj->type));
|
|
|
|
if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, templargs, 0)) {
|
|
arg = TYPE_FUNC(funcobj->type)->args;
|
|
if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(funcobj->type))) {
|
|
CError_ASSERT(1664, arg);
|
|
arg = arg->next;
|
|
}
|
|
|
|
while (1) {
|
|
if (!arg || arg->type == &stvoid) {
|
|
if (argexprs)
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
if (arg == &elipsis)
|
|
break;
|
|
if (arg == &oldstyle)
|
|
break;
|
|
|
|
if (!argexprs) {
|
|
if (arg->dexpr)
|
|
break;
|
|
return NULL;
|
|
}
|
|
|
|
ctempl_explicitargs_nindex = info.x12C;
|
|
ctempl_explicitargs_num = info.count;
|
|
ctempl_explicitargs_all = 1;
|
|
|
|
if (CTempl_TypeNeedsDeduction(arg->type) && !ctempl_explicitargs_all) {
|
|
ENode *node = argexprs->node;
|
|
|
|
if (ENODE_IS(node, EOBJREF) && IS_TEMPL_FUNC(node->data.objref->type))
|
|
return NULL;
|
|
|
|
if (ENODE_IS(node, EOBJLIST)) {
|
|
if (!CExpr_DeduceFromObjList(arg, node->data.objlist.list, &info))
|
|
return NULL;
|
|
} else {
|
|
if (!CTempl_DeduceType(
|
|
arg->type, arg->qual & (Q_CONST | Q_VOLATILE),
|
|
node->rtype, ENODE_QUALS(node),
|
|
info.args, 1, 0))
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
argexprs = argexprs->next;
|
|
arg = arg->next;
|
|
}
|
|
|
|
for (i = 0; i < info.maxCount; i++) {
|
|
if (!info.args[i].is_deduced)
|
|
return 0;
|
|
info.args[i].next = &info.args[i + 1];
|
|
}
|
|
info.args[info.maxCount].next = NULL;
|
|
|
|
return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
Object *CTempl_DeduceFromConversion(Object *funcobj, Type *type, UInt32 qual) {
|
|
DeduceInfo info;
|
|
int i;
|
|
|
|
CError_ASSERT(1745, IS_TEMPL_FUNC(funcobj->type));
|
|
|
|
if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, NULL, 0))
|
|
return NULL;
|
|
|
|
ctempl_explicitargs_nindex = info.x12C;
|
|
ctempl_explicitargs_num = info.count;
|
|
ctempl_explicitargs_all = 1;
|
|
|
|
if (!CTempl_TypeNeedsDeduction(TYPE_FUNC(funcobj->type)->functype))
|
|
return NULL;
|
|
|
|
if (!CTempl_DeduceType(TYPE_FUNC(funcobj->type)->functype, TYPE_FUNC(funcobj->type)->qual, type, qual, info.args, 0, 1))
|
|
return NULL;
|
|
|
|
for (i = 0; i < info.maxCount; i++) {
|
|
if (!info.args[i].is_deduced)
|
|
return 0;
|
|
info.args[i].next = &info.args[i + 1];
|
|
}
|
|
info.args[info.maxCount].next = NULL;
|
|
|
|
return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object;
|
|
}
|
|
|
|
static int CTemplFunc_TemplateNestLevel(NameSpace *nspace) {
|
|
int level = 0;
|
|
|
|
while (nspace) {
|
|
if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_900))
|
|
level++;
|
|
nspace = nspace->parent;
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
static Boolean CTemplFunc_SameFuncType(TypeFunc *a, TypeFunc *b) {
|
|
FuncArg *arg1;
|
|
FuncArg *arg2;
|
|
|
|
CError_ASSERT(1800, IS_TYPE_FUNC(a) && IS_TYPE_FUNC(b));
|
|
|
|
if (!is_typesame(a->functype, b->functype))
|
|
return 0;
|
|
|
|
if (a->qual != b->qual)
|
|
return 0;
|
|
|
|
if ((a->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000)) != (b->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000)))
|
|
return 0;
|
|
|
|
arg1 = a->args;
|
|
if ((a->flags & FUNC_FLAGS_METHOD) && !TYPE_METHOD(a)->x26) {
|
|
CError_ASSERT(1808, arg1);
|
|
arg1 = arg1->next;
|
|
}
|
|
|
|
arg2 = b->args;
|
|
if ((b->flags & FUNC_FLAGS_METHOD) && !TYPE_METHOD(b)->x26) {
|
|
CError_ASSERT(1814, arg2);
|
|
arg2 = arg2->next;
|
|
}
|
|
|
|
return is_arglistsame(arg1, arg2);
|
|
}
|
|
|
|
Object *CTempl_TemplateFunctionCheck(DeclInfo *di, NameSpaceObjectList *nsol) {
|
|
TemplArg *arg;
|
|
TemplFuncInstance *inst;
|
|
Object *object;
|
|
|
|
for (arg = di->expltargs; arg; arg = arg->next) {
|
|
switch (arg->pid.type) {
|
|
case TPT_TYPE:
|
|
if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
|
|
break;
|
|
continue;
|
|
case TPT_NONTYPE:
|
|
if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
|
|
break;
|
|
continue;
|
|
default:
|
|
CError_FATAL(1844);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (arg) {
|
|
while (nsol) {
|
|
object = OBJECT(nsol->object);
|
|
if (
|
|
object->otype == OT_OBJECT &&
|
|
IS_TEMPL_FUNC(object->type) &&
|
|
CTemplTool_IsSameTemplate(CTemplTool_GetFuncTempl(object)->params, di->expltargs) &&
|
|
CTemplFunc_SameFuncType(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(di->thetype))
|
|
)
|
|
return OBJECT(nsol->object);
|
|
|
|
nsol = nsol->next;
|
|
}
|
|
} else {
|
|
while (nsol) {
|
|
object = OBJECT(nsol->object);
|
|
if (
|
|
object->otype == OT_OBJECT &&
|
|
IS_TEMPL_FUNC(object->type) &&
|
|
(inst = CTempl_DeduceFunc(object, TYPE_FUNC(di->thetype), di->expltargs, NULL, 1))
|
|
)
|
|
{
|
|
if (di->x3C) {
|
|
if (!(di->qual & Q_INLINE)) {
|
|
if (!inst->is_specialized)
|
|
inst->object->qual &= ~Q_INLINE;
|
|
} else {
|
|
inst->object->qual |= Q_INLINE;
|
|
}
|
|
|
|
if (!inst->is_specialized && inst->is_instantiated)
|
|
CError_Error(CErrorStr335);
|
|
|
|
if (di->x3C != (CTemplFunc_TemplateNestLevel(inst->object->nspace) + 1))
|
|
CError_Warning(CErrorStr335);
|
|
|
|
inst->is_specialized = 1;
|
|
di->x3C = 0;
|
|
}
|
|
|
|
CTemplTool_MergeArgNames(TYPE_FUNC(di->thetype), TYPE_FUNC(inst->object->type));
|
|
di->x38 = CTemplTool_GetFuncTempl(OBJECT(nsol->object));
|
|
return inst->object;
|
|
}
|
|
nsol = nsol->next;
|
|
}
|
|
}
|
|
|
|
CError_ResetErrorSkip();
|
|
CError_Error(CErrorStr335);
|
|
di->x3C = 0;
|
|
return NULL;
|
|
}
|