From 817c700ced95b2fc615e1619c89fcec21f66af55 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 30 Jan 2023 08:22:33 +0000 Subject: [PATCH] Template partial specialization improvements Closes #1300 Changes to support the first example below (partial specialization of template parameter types like Vect). Previous implementation and design could only handle one template parameter name per template specialization argument, such as Vect for the first template specialization argument (for first example below) template class Foo, int> { ... }; and not template class Foo, int> { ... }; New approach is to not modify 'templateparms' in the template node, (except to fill in default args from primary template) Previous implementation also assumed a template parameter could not be used more than once in the specialized arguments, such as template struct Hey { void specialA() {} }; Examples ======== 1) For primary: template class Foo { ... }; and specialization: template class Foo, TTS> { ... }; Fix specialization template from (wrong) | templateparms - 'Vect< TS >,typename TTS' to (correct/new way) | templateparms - 'class TS,typename TTS' 2) For primary: template struct Partialler { void primary(P1, P2) {}; }; and specialization: template struct Partialler { void special(S1*, S2, bool) {}; }; Specialized template changes from (wrong) | templateparms - 'typename S2=int,typename S1=double' to (correct/new way, default args are removed) | templateparms - 'typename S1,typename S2' and subsequent change to partialargs from | partialargs - "Partialler<($1,p.$2)>" to | partialargs - "Partialler<($2,p.$1)>" so that the $n number is now more logically the nth template parameter in templateparms 3) For primary: template struct Hey { void primary() {} }; and specialization: template struct Hey { void specialA() {} }; old (wrong/old way) | templateparms - 'typename T,typename T' new (correct/new way) | templateparms - 'typename T' These are unchanged and are okay: | partialargs - "Hey<($1,$1)>" 4) For primary: enum Hello { hi, hello }; template struct C {}; and specialization: template struct C { ... }; old (wrong/old way) | templateparms - 'hello,class A' new (correct/new way) | templateparms - 'class A' and subsequent changes to partialargs from | partialargs - "C<(hi,$2)>" to | partialargs - "C<(hi,$1)>" Test-suite ========== Identical output as before in Python but in Java, an unimportant change in cpp11_variadic_function_templates.i results in one variadic parameter name being different. New testcase template_partial_specialization_more.i with more testcases added including above examples that are not already in the test-suite. --- CHANGES.current | 18 ++ Examples/test-suite/common.mk | 1 + .../template_partial_specialization_more.i | 103 ++++++++ Source/CParse/cparse.h | 2 +- Source/CParse/parser.y | 105 +------- Source/CParse/templ.c | 249 ++++++++++++------ 6 files changed, 309 insertions(+), 169 deletions(-) create mode 100644 Examples/test-suite/template_partial_specialization_more.i diff --git a/CHANGES.current b/CHANGES.current index 54813b0d3..2c9c85330 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,24 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.2.0 (in progress) =========================== +2023-02-15: wsfulton + #1300 Further partial template specialization fixes. + Fixes when templates are used as a template parameter in a partially specialized + instantiation such as: + + template struct Vect {}; + template class Foo { ... }; + template class Foo, TTS> { ... }; + %template(VectInt) Vect; + %template(FooVectIntDouble) Foo, double>; // was previously attempting to use primary template + + Also fixes partial specialization where the same template parameter name is used twice, + for example: + + template struct H { ... }; + template struct H { ... }; + %template(HInts) H; // was previously attempting to use primary template + 2023-01-27: jschueller #2492 [python] Fix unused parameter warnings for self parameter in generated C/C++ wrapper code. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index a0f35c5ac..db2a3d6f7 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -487,6 +487,7 @@ CPP_TEST_CASES += \ template_parameters_global_scope \ template_partial_arg \ template_partial_specialization \ + template_partial_specialization_more \ template_partial_specialization_typedef \ template_qualifier \ template_ref_type \ diff --git a/Examples/test-suite/template_partial_specialization_more.i b/Examples/test-suite/template_partial_specialization_more.i new file mode 100644 index 000000000..620a5625b --- /dev/null +++ b/Examples/test-suite/template_partial_specialization_more.i @@ -0,0 +1,103 @@ +%module template_partial_specialization_more + + +// (1) Based on https://stackoverflow.com/questions/9757642/wrapping-specialised-c-template-class-with-swig +%inline %{ +template struct Vect {}; +template +class Foo { +public: + Foo() {} + virtual ~Foo() {} + T primary() const { return T(); } +}; + +template +class Foo, TTS> { +public: + Foo() {} + virtual ~Foo() {} + TS partially_specialized(TS parmin) const { return parmin; } +}; +template<> +class Foo, double> { +public: + Foo() {} + virtual ~Foo() {} + double value_fully_specialized(double d) const { return d; } +}; +template +class Foo { +public: + Foo() {} + virtual ~Foo() {} + int pointer_specialize(T myT) const { return 0; } +}; +%} +%template(VectInt) Vect; +%template(FooVectIntDouble) Foo, double>; // was failing +%template(FooShortPtrDouble) Foo; +%template(FooVectVectInt) Foo>, int>; // was failing + + +// (2) Same types in both args +%inline %{ +template struct Hey { void primary() {} }; +template struct Hey { void special_hey() {} }; +%} +%template(HeyInts) Hey; // was failing, was calling primary + + +// (3) Partial specialization using one template parameter instead of two +%inline %{ + struct PlainStruct {}; + template struct XX { void primary() {} }; + template struct XX { void special1() {} }; // r.$1 + template struct XX { void special2() {} }; // r.q(const).$1 + template struct XX { void special3() {} }; // r.q(const).p.$1 +%} +%template(XX1) XX; // was failing, was calling primary +%template(XX2) XX; +%template(XX3) XX; + + +// (4) Switching parameters around +%inline %{ +#include +template struct Partialler { void primary(P1, P2) {}; }; +template struct Partialler { void special(S1*, S2, bool) {}; }; +%} +%template(PartiallerPrimary) Partialler; +%template(PartiallerSpecial) Partialler; + + +// (5) Default args used in specialization, like std::list +%inline %{ +template struct Allocator {}; +template > struct Lyst { void primary(T, Allocator) {} }; +template struct Lyst { void specialized1(TT, XXAlloc) {} }; +template struct Lyst> { void specialized2(TTT, YY) {} }; +// TODO Error: Inconsistent argument count in template partial specialization. 1 2 +//template struct Lyst { void specialized3(TTTT) {} }; +void test_list() { + int myint = 0; + Lyst lis; + lis.primary(myint, Allocator()); + + PlainStruct ps; + Lyst liss; + liss.specialized1(ps, Allocator()); + + double mydouble = 0; + Lyst lissd; + lissd.specialized2(mydouble, (double **)nullptr); + +// Lyst lissconstint; +// lissconstint.specialized3(myint); +} +%} + +%template(LystDouble) Lyst; +//%template(LystDouble) Lyst>; +%template(LystPlainStructPtr) Lyst; +%template(LystDoublePtrPtr) Lyst; // called specialized1 instead of specialized2 diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h index 039e97de7..db050eb91 100644 --- a/Source/CParse/cparse.h +++ b/Source/CParse/cparse.h @@ -68,7 +68,7 @@ extern "C" { extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope); extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, String *symname, Symtab *tscope); extern void Swig_cparse_debug_templates(int); - extern ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary); + extern ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary, Node *templ); #ifdef __cplusplus } diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index c66b60db6..df2a87a91 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -2883,7 +2883,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Node *primary_template = Swig_symbol_clookup(tname, 0); /* Expand the template */ - ParmList *temparms = Swig_cparse_template_parms_expand($7, primary_template); + ParmList *temparms = Swig_cparse_template_parms_expand($7, primary_template, nn); templnode = copy_node(nn); update_nested_classes(templnode); /* update classes nested within template */ @@ -4128,112 +4128,32 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { if (!Getattr($$,"sym:weak")) { Setattr($$,"sym:typename","1"); } + Setattr($$, "primarytemplate", tempn); + Setattr($$, "templateparms", $3); + Delattr($$, "specialization"); + Setattr($$, "partialspecialization", "1"); if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) { Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms"))); } else { - - /* This code builds the argument list for the partial template - specialization. This is a little hairy, but the idea is as - follows: - - $3 contains a list of arguments supplied for the template. - For example template. - - tlist is a list of the specialization arguments--which may be - different. For example class. - - tp is a copy of the arguments in the original template definition. - - The patching algorithm walks through the list of supplied - arguments ($3), finds the position in the specialization arguments - (tlist), and then patches the name in the argument list of the - original template. - */ - - { - String *pn; - Parm *p, *p1; - int i, nargs; - Parm *tp = CopyParmList(Getattr(tempn,"templateparms")); - nargs = Len(tlist); - p = $3; - while (p) { - for (i = 0; i < nargs; i++){ - pn = Getattr(p,"name"); - if (Strcmp(pn,SwigType_base(Getitem(tlist,i))) == 0) { - int j; - Parm *p1 = tp; - for (j = 0; j < i; j++) { - p1 = nextSibling(p1); - } - Setattr(p1,"name",pn); - Setattr(p1,"partialarg","1"); - } - } - p = nextSibling(p); - } - p1 = tp; - i = 0; - while (p1) { - if (!Getattr(p1,"partialarg")) { - Delattr(p1,"name"); - Setattr(p1,"type", Getitem(tlist,i)); - } - i++; - p1 = nextSibling(p1); - } - Setattr($$,"templateparms",tp); - Delete(tp); - } - #if 0 - /* Patch the parameter list */ - if (tempn) { - Parm *p,*p1; - ParmList *tp = CopyParmList(Getattr(tempn,"templateparms")); - p = $3; - p1 = tp; - while (p && p1) { - String *pn = Getattr(p,"name"); - Printf(stdout,"pn = '%s'\n", pn); - if (pn) Setattr(p1,"name",pn); - else Delattr(p1,"name"); - pn = Getattr(p,"type"); - if (pn) Setattr(p1,"type",pn); - p = nextSibling(p); - p1 = nextSibling(p1); - } - Setattr($$,"templateparms",tp); - Delete(tp); - } else { - Setattr($$,"templateparms",$3); - } - #endif - Delattr($$,"specialization"); - Setattr($$,"partialspecialization","1"); - /* Create a specialized name for matching */ - { + /* Create a specialized name with template parameters replaced with $ variables, such as, X<(T1,p.T2) => X<($1,p.$2)> */ Parm *p = $3; String *fname = NewString(Getattr($$,"name")); String *ffname = 0; ParmList *partialparms = 0; char tmp[32]; - int i, ilen; + int i = 0; while (p) { - String *n = Getattr(p,"name"); - if (!n) { + String *name = Getattr(p,"name"); + ++i; + if (!name) { p = nextSibling(p); continue; } - ilen = Len(tlist); - for (i = 0; i < ilen; i++) { - if (Strstr(Getitem(tlist,i),n)) { - sprintf(tmp,"$%d",i+1); - Replaceid(fname,n,tmp); - } - } + sprintf(tmp, "$%d", i); + Replaceid(fname, name, tmp); p = nextSibling(p); } /* Patch argument names with typedef */ @@ -4279,7 +4199,6 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { Setattr($$,"partialargs",ffname); Swig_symbol_cadd(ffname,$$); } - } Delete(tlist); Delete(targs); } else { diff --git a/Source/CParse/templ.c b/Source/CParse/templ.c index 7a4d0cf4f..a126ad29c 100644 --- a/Source/CParse/templ.c +++ b/Source/CParse/templ.c @@ -13,6 +13,7 @@ #include "swig.h" #include "cparse.h" +#include static int template_debug = 0; @@ -396,25 +397,43 @@ static void cparse_postprocess_expanded_template(Node *n) { /* ----------------------------------------------------------------------------- * partial_arg() + * + * Return a parameter with type that matches the specialized template argument. + * If the input has no partial type, the name is not set in the returned parameter. + * + * type: an instantiated template parameter type, for example: Vect<(int)> + * partialtype: type from specialized template where parameter name has been + * replaced by a $ variable, for example: Vect<($1)> + * + * Returns a parameter of type 'int' and name $1 for the two example parameters above. * ----------------------------------------------------------------------------- */ -static String *partial_arg(String *s, String *p) { - char *c; - char *cp = Char(p); - String *prefix; - String *newarg; +static Parm *partial_arg(const SwigType *type, const SwigType *partialtype) { + SwigType *parmtype; + String *parmname = 0; + const char *cp = Char(partialtype); + const char *c = strchr(cp, '$'); - /* Find the prefix on the partial argument */ - - c = strchr(cp, '$'); - if (!c) { - return Copy(s); + if (c) { + int suffix_length; + int prefix_length = c - cp; + int type_length = Len(type); + const char *suffix = c; + String *prefix = NewStringWithSize(cp, prefix_length); + while (++suffix) { + if (!isdigit((int)*suffix)) + break; + } + parmname = NewStringWithSize(c, suffix - c); /* $1, $2 etc */ + suffix_length = strlen(suffix); + assert(Strstr(type, prefix) == Char(type)); /* check that the start of both types match */ + assert(strcmp(Char(type) + type_length - suffix_length, suffix) == 0); /* check that the end of both types match */ + parmtype = NewStringWithSize(Char(type) + prefix_length, type_length - suffix_length - prefix_length); + Delete(prefix); + } else { + parmtype = Copy(type); } - prefix = NewStringWithSize(cp, (int)(c - cp)); - newarg = Copy(s); - Replace(newarg, prefix, "", DOH_REPLACE_FIRST); - Delete(prefix); - return newarg; + return NewParmWithoutFileLineInfo(parmtype, parmname); } /* ----------------------------------------------------------------------------- @@ -429,6 +448,8 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab String *tbase; Parm *unexpanded_variadic_parm = 0; ParmList *expanded_variadic_parms = 0; + ParmList *templateparms = Getattr(n, "templateparms"); + ParmList *templateparmsraw = 0; patchlist = NewList(); /* List of String * ("name" and "value" attributes) */ cpatchlist = NewList(); /* List of String * (code) */ typelist = NewList(); /* List of SwigType * types */ @@ -439,12 +460,13 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab tname = Copy(Getattr(n, "name")); tbase = Swig_scopename_last(tname); - /* Look for partial specialization matching */ if (Getattr(n, "partialargs")) { + /* Partial specialization */ Parm *p, *tp; ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"), n); p = ptargs; tp = tparms; + /* Adjust templateparms so that the type is expanded, eg typename => int */ while (p && tp) { SwigType *ptype; SwigType *tptype; @@ -453,9 +475,20 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab tptype = Getattr(tp, "type"); if (ptype && tptype) { SwigType *ty = Swig_symbol_typedef_reduce(tptype, tscope); - partial_type = partial_arg(ty, ptype); + Parm *partial_parm = partial_arg(ty, ptype); + String *partial_name = Getattr(partial_parm, "name"); + partial_type = Copy(Getattr(partial_parm, "type")); /* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */ - Setattr(tp, "type", partial_type); + if (partial_name && strchr(Char(partial_name), '$') == Char(partial_name)) { + int index = atoi(Char(partial_name) + 1) - 1; + assert(index >= 0); + Parm *parm = ParmList_nth_parm(templateparms, index); + assert(parm); + if (parm) { + Setattr(parm, "type", partial_type); + } + } + Delete(partial_parm); Delete(partial_type); Delete(ty); } @@ -464,20 +497,17 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab } assert(ParmList_len(ptargs) == ParmList_len(tparms)); Delete(ptargs); + } else { + Setattr(n, "templateparmsraw", Getattr(n, "templateparms")); + templateparms = CopyParmList(tparms); + Setattr(n, "templateparms", templateparms); } - /* - Parm *p = tparms; - while (p) { - Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value")); - p = nextSibling(p); - } - */ - - ParmList *templateparms = Getattr(n, "templateparms"); - unexpanded_variadic_parm = ParmList_variadic_parm(templateparms); + /* TODO: variadic parms for partially specialized templates */ + templateparmsraw = Getattr(n, "templateparmsraw"); + unexpanded_variadic_parm = ParmList_variadic_parm(templateparmsraw); if (unexpanded_variadic_parm) - expanded_variadic_parms = ParmList_nth_parm(tparms, ParmList_len(templateparms) - 1); + expanded_variadic_parms = ParmList_nth_parm(templateparms, ParmList_len(templateparmsraw) - 1); /* Printf(stdout,"targs = '%s'\n", templateargs); Printf(stdout,"rname = '%s'\n", rname); @@ -496,24 +526,23 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab /* Patch all of the types */ { Parm *tp = Getattr(n, "templateparms"); - Parm *p = tparms; /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ - if (p && tp) { + if (tp) { Symtab *tsdecl = Getattr(n, "sym:symtab"); String *tsname = Getattr(n, "sym:name"); - while (p && tp) { + while (tp) { String *name, *value, *valuestr, *tmp, *tmpr; int sz, i; String *dvalue = 0; String *qvalue = 0; name = Getattr(tp, "name"); - value = Getattr(p, "value"); + value = Getattr(tp, "value"); if (name) { if (!value) - value = Getattr(p, "type"); + value = Getattr(tp, "type"); qvalue = Swig_symbol_typedef_reduce(value, tsdecl); dvalue = Swig_symbol_type_qualify(qvalue, tsdecl); if (SwigType_istemplate(dvalue)) { @@ -524,17 +553,6 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab assert(dvalue); valuestr = SwigType_str(dvalue, 0); - /* Need to patch default arguments */ - { - Parm *rp = nextSibling(p); - while (rp) { - String *rvalue = Getattr(rp, "value"); - if (rvalue) { - Replace(rvalue, name, dvalue, DOH_REPLACE_ID); - } - rp = nextSibling(rp); - } - } sz = Len(patchlist); for (i = 0; i < sz; i++) { String *s = Getitem(patchlist, i); @@ -580,10 +598,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab Delete(dvalue); Delete(qvalue); } - p = nextSibling(p); tp = nextSibling(tp); - if (!p) - p = tp; } } else { /* No template parameters at all. This could be a specialization */ @@ -625,26 +640,47 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpecializedMatch = 1, ExactMatch = 2 } EMatch; +/* ----------------------------------------------------------------------------- + * is_exact_partial_type() + * + * Return 1 if parm matches $1, $2, $3 etc exactly without any other prefixes or + * suffixes. Return 0 otherwise. + * ----------------------------------------------------------------------------- */ + +static int is_exact_partial_type(const SwigType *type) { + const char *c = Char(type); + int is_exact = 0; + if (*c == '$' && isdigit((int)*(c + 1))) { + const char *suffix = c + 1; + while (++suffix) { + if (!isdigit((int)*suffix)) + break; + } + is_exact = (*suffix == 0); + } + return is_exact; +} + /* ----------------------------------------------------------------------------- * does_parm_match() * - * Template argument deduction - check if a template type matches a partially specialized + * Template argument deduction - check if a template type matches a partially specialized * template parameter type. Typedef reduce 'partial_parm_type' to see if it matches 'type'. * * type - template parameter type to match against * partial_parm_type - specialized template type, for example, r.$1 (partially specialized) or r.int (fully specialized) - * partial_parm - partially specialized template parameter name, such as, $1 or $2 or $3, etc * tscope - template scope - * specialization_priority - (output) contains a value indicating how good the match is + * specialization_priority - (output) contains a value indicating how good the match is * (higher is better) only set if return is set to PartiallySpecializedMatch or ExactMatch. * ----------------------------------------------------------------------------- */ -static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const char *partial_parm, Symtab *tscope, int *specialization_priority) { +static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, Symtab *tscope, int *specialization_priority) { static const int EXACT_MATCH_PRIORITY = 99999; /* a number bigger than the length of any conceivable type */ + static const int TEMPLATE_MATCH_PRIORITY = 1000; /* a priority added for each nested template, assumes max length of any prefix, such as r.q(const). , is less than this number */ SwigType *ty = Swig_symbol_typedef_reduce(type, tscope); SwigType *pp_prefix = SwigType_prefix(partial_parm_type); int pp_len = Len(pp_prefix); - EMatch match = Strstr(partial_parm_type, partial_parm) == 0 ? ExactNoMatch : PartiallySpecializedNoMatch; + EMatch match = Strchr(partial_parm_type, '$') == 0 ? ExactNoMatch : PartiallySpecializedNoMatch; *specialization_priority = -1; if (Equal(ty, partial_parm_type)) { @@ -653,27 +689,89 @@ static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const } else if (match == PartiallySpecializedNoMatch) { if ((pp_len > 0 && Strncmp(ty, pp_prefix, pp_len) == 0)) { /* - type starts with pp_prefix, so it is a partial specialization type match, for example, + Type starts with pp_prefix, so it is a partial specialization type match, for example, all of the following could match the type in the %template: - template struct XX {}; - template struct XX {}; // r.$1 - template struct XX {}; // r.q(const).$1 - template struct XX {}; // r.q(const).p.$1 - %template(XXX) XX; // r.q(const).p.int - + template struct XX {}; + template struct XX {}; // r.$1 + template struct XX {}; // r.q(const).$1 + template struct XX {}; // r.q(const).p.$1 + %template(XXX) XX; // r.q(const).p.int where type="r.q(const).p.int" will match either of pp_prefix="r.", pp_prefix="r.q(const)." pp_prefix="r.q(const).p." */ match = PartiallySpecializedMatch; *specialization_priority = pp_len; - } else if (pp_len == 0 && Equal(partial_parm_type, partial_parm)) { + } else if (pp_len == 0 && is_exact_partial_type(partial_parm_type)) { /* - type without a prefix match, as in $1 for int - template struct XX {}; - template struct XX {}; // $1,r.$2 - %template(XXX) XX; // int,r.double + Type without a prefix match, as in $1 for int + template struct XX {}; + template struct XX {}; // $1,r.$2 + %template(XXX) XX; // int,r.double */ match = PartiallySpecializedMatch; *specialization_priority = pp_len; + } else { + /* + Check for template types that are templates such as + template struct Vect {}; + template class XX {}; + template class XX> {}; + %template(XXVectInt) XX>; + matches type="Vect<(int)>" and partial_parm_type="Vect<($1)>" + */ + if (SwigType_istemplate(partial_parm_type) && SwigType_istemplate(ty)) { + + SwigType *qt = Swig_symbol_typedef_reduce(ty, tscope); + String *tsuffix = SwigType_templatesuffix(qt); + + SwigType *pp_qt = Swig_symbol_typedef_reduce(partial_parm_type, tscope); + String *pp_tsuffix = SwigType_templatesuffix(pp_qt); + + if (Equal(tsuffix, pp_tsuffix) && Len(tsuffix) == 0) { + String *tprefix = SwigType_templateprefix(qt); + String *qprefix = SwigType_typedef_qualified(tprefix); + + String *pp_tprefix = SwigType_templateprefix(pp_qt); + String *pp_qprefix = SwigType_typedef_qualified(pp_tprefix); + + if (Equal(qprefix, pp_qprefix)) { + String *templateargs = SwigType_templateargs(qt); + List *parms = SwigType_parmlist(templateargs); + Iterator pi = First(parms); + Parm *p = pi.item; + + String *pp_templateargs = SwigType_templateargs(pp_qt); + List *pp_parms = SwigType_parmlist(pp_templateargs); + Iterator pp_pi = First(pp_parms); + Parm *pp = pp_pi.item; + + if (p && pp) { + /* Implementation is limited to matching single parameter templates only for now */ + int priority; + match = does_parm_match(p, pp, tscope, &priority); + if (match <= PartiallySpecializedNoMatch) { + *specialization_priority = priority; + } else { + *specialization_priority = priority + TEMPLATE_MATCH_PRIORITY; + } + } + + Delete(pp_parms); + Delete(pp_templateargs); + Delete(parms); + Delete(templateargs); + } + + Delete(pp_qprefix); + Delete(pp_tprefix); + Delete(qprefix); + Delete(tprefix); + } + + Delete(pp_tsuffix); + Delete(pp_qt); + Delete(tsuffix); + Delete(qt); + } } } /* @@ -828,7 +926,6 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym /* Rank each template parameter against the desired template parameters then build a matrix of best matches */ possiblepartials = NewList(); { - char tmp[32]; List *partials; partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */ @@ -852,12 +949,11 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym if (ParmList_len(partialparms) == parms_len) { while (p && pp) { SwigType *t; - sprintf(tmp, "$%d", i); t = Getattr(p, "type"); if (!t) t = Getattr(p, "value"); if (t) { - EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1); + EMatch match = does_parm_match(t, Getattr(pp, "type"), tscope, priorities_row + i - 1); if (match < (int)PartiallySpecializedMatch) { all_parameters_match = 0; break; @@ -1062,7 +1158,8 @@ Node *Swig_cparse_template_locate(String *name, Parm *instantiated_parms, String isclass = (Equal(Getattr(n, "templatetype"), "class")); if (isclass) { - Parm *tparmsfound = Getattr(n, "templateparms"); + Node *primary = Getattr(n, "primarytemplate"); + Parm *tparmsfound = Getattr(primary ? primary : n, "templateparms"); int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */ int variadic = ParmList_variadic_parm(tparmsfound) != 0; if (!specialized) { @@ -1171,15 +1268,16 @@ static int merge_parameters(ParmList *expanded_templateparms, ParmList *template } /* ----------------------------------------------------------------------------- - * mark_defaults() + * use_mark_defaults() * - * Mark all the template parameters that are expanded from a default value + * Mark and use all the template parameters that are expanded from a default value * ----------------------------------------------------------------------------- */ -static void mark_defaults(ParmList *defaults) { +static void use_mark_defaults(ParmList *defaults) { Parm *tp = defaults; while (tp) { Setattr(tp, "default", "1"); + Setattr(tp, "type", Getattr(tp, "value")); tp = nextSibling(tp); } } @@ -1222,12 +1320,12 @@ static void expand_defaults(ParmList *expanded_templateparms) { * arguments filled in where necessary. * ----------------------------------------------------------------------------- */ -ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary) { +ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary, Node *templ) { ParmList *expanded_templateparms = 0; - ParmList *templateparms = Getattr(primary, "templateparms"); if (Equal(Getattr(primary, "templatetype"), "class")) { /* Templated class */ + ParmList *templateparms = Getattr(primary, "templateparms"); expanded_templateparms = CopyParmList(instantiated_parms); int variadic = merge_parameters(expanded_templateparms, templateparms); /* Add default arguments from primary template */ @@ -1235,7 +1333,7 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node * ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parms)); if (defaults_start) { ParmList *defaults = CopyParmList(defaults_start); - mark_defaults(defaults); + use_mark_defaults(defaults); expanded_templateparms = ParmList_join(expanded_templateparms, defaults); expand_defaults(expanded_templateparms); } @@ -1243,6 +1341,7 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node * } else { /* Templated function */ /* TODO: Default template parameters support was only added in C++11 */ + ParmList *templateparms = Getattr(templ, "templateparms"); expanded_templateparms = CopyParmList(instantiated_parms); merge_parameters(expanded_templateparms, templateparms); }