Support multiple arguments in variadic templates.

Remove warning SWIGWARN_CPP11_VARIADIC_TEMPLATE which was issued if more
than one argument was used for a variadic template.

SwigType enhancement: 'v.' now represents a variadic argument.
This commit is contained in:
William S Fulton 2022-12-18 14:16:46 +00:00
commit 67c4c2186c
13 changed files with 465 additions and 66 deletions

View file

@ -439,7 +439,6 @@ example.i(4) : Syntax error in input(1).
<li>326. Deprecated %extend name used - the <em>kind</em> name '<em>name</em>' should be used instead of the typedef name '<em>name</em>'. <li>326. Deprecated %extend name used - the <em>kind</em> name '<em>name</em>' should be used instead of the typedef name '<em>name</em>'.
<li>327. Extern template ignored. <li>327. Extern template ignored.
<li>340. Lambda expressions and closures are not fully supported yet. <li>340. Lambda expressions and closures are not fully supported yet.
<li>343. Only the first variadic template argument is currently supported.
<li>344. Unable to deduce decltype for '<em>expr</em>'. <li>344. Unable to deduce decltype for '<em>expr</em>'.
<li>350. operator new ignored. <li>350. operator new ignored.
<li>351. operator delete ignored. <li>351. operator delete ignored.

View file

@ -632,10 +632,10 @@ CPP11_TEST_CASES += \
cpp11_uniform_initialization \ cpp11_uniform_initialization \
cpp11_unrestricted_unions \ cpp11_unrestricted_unions \
cpp11_userdefined_literals \ cpp11_userdefined_literals \
cpp11_variadic_templates \
# Broken C++11 test cases. # Broken C++11 test cases.
CPP11_TEST_BROKEN = \ CPP11_TEST_BROKEN = \
# cpp11_variadic_templates \ # Broken for some languages (such as Java)
# cpp11_reference_wrapper \ # No typemaps # cpp11_reference_wrapper \ # No typemaps
# C++14 test cases. # C++14 test cases.

View file

@ -4,9 +4,21 @@
using variadic number of classes. using variadic number of classes.
*/ */
%module cpp11_variadic_templates %module cpp11_variadic_templates
%warnfilter(SWIGWARN_CPP11_VARIADIC_TEMPLATE) MultiArgs; %warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE,
%warnfilter(SWIGWARN_CPP11_VARIADIC_TEMPLATE) SizeOf; SWIGWARN_CSHARP_MULTIPLE_INHERITANCE,
%warnfilter(SWIGWARN_CPP11_VARIADIC_TEMPLATE) MultiInherit; SWIGWARN_D_MULTIPLE_INHERITANCE,
SWIGWARN_PHP_MULTIPLE_INHERITANCE,
SWIGWARN_RUBY_MULTIPLE_INHERITANCE) MultiInherit;
%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE,
SWIGWARN_CSHARP_MULTIPLE_INHERITANCE,
SWIGWARN_D_MULTIPLE_INHERITANCE,
SWIGWARN_PHP_MULTIPLE_INHERITANCE,
SWIGWARN_RUBY_MULTIPLE_INHERITANCE) NumerousInherit;
%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE,
SWIGWARN_CSHARP_MULTIPLE_INHERITANCE,
SWIGWARN_D_MULTIPLE_INHERITANCE,
SWIGWARN_PHP_MULTIPLE_INHERITANCE,
SWIGWARN_RUBY_MULTIPLE_INHERITANCE) LotsInherit;
//////////////////////// ////////////////////////
// Variadic templates // // Variadic templates //
@ -24,7 +36,6 @@ class MultiArgs<int, std::vector<int>, std::map<std::string, std::vector<int>>>
%} %}
// TODO
%template (MultiArgs1) MultiArgs<int, std::vector<int>, std::map<std::string, std::vector<int>>>; %template (MultiArgs1) MultiArgs<int, std::vector<int>, std::map<std::string, std::vector<int>>>;
//////////////////////// ////////////////////////
@ -36,7 +47,10 @@ template<typename... Args> struct SizeOf {
}; };
%} %}
%template (SizeOf1) SizeOf<int, int>; %template (SizeOf0) SizeOf<>;
%template (SizeOf1) SizeOf<int>;
%template (SizeOf2) SizeOf<int, int>;
%template (SizeOf3) SizeOf<int, int, int>;
////////////////////////// //////////////////////////
// Variadic inheritance // // Variadic inheritance //
@ -60,18 +74,67 @@ public:
int b; int b;
}; };
class C {
public:
C() {
c = 300;
}
virtual ~C() {}
int c;
};
class D {
public:
D() {
d = 400;
}
virtual ~D() {}
int d;
};
template <typename... BaseClasses> class MultiInherit : public BaseClasses... { template <typename... BaseClasses> class MultiInherit : public BaseClasses... {
public: public:
MultiInherit(BaseClasses&... baseClasses) : BaseClasses(baseClasses)... {} MultiInherit(BaseClasses&... baseClasses) : BaseClasses(baseClasses)... {}
void MultiInstanceMethod(BaseClasses&... baseClasses) {}
static void MultiStaticMethod(BaseClasses&... baseClasses) {}
int InstanceMethod() { return 123; } int InstanceMethod() { return 123; }
static int StaticMethod() { return 456; } static int StaticMethod() { return 456; }
}; };
%} %}
%template (MultiInherit0) MultiInherit<>;
// TODO
//%template (MultiInherit0) MultiInherit<>;
%template (MultiInherit1) MultiInherit<A>; %template (MultiInherit1) MultiInherit<A>;
// TODO
%template (MultiInherit2) MultiInherit<A,B>; %template (MultiInherit2) MultiInherit<A,B>;
%template (MultiInherit3) MultiInherit<A,B,C>;
%inline %{
template <typename... BaseClasses> class NumerousInherit : public BaseClasses... {
public:
NumerousInherit(int i, BaseClasses&... baseClasses) : BaseClasses(baseClasses)... {}
void NumerousInstanceMethod(int i, BaseClasses&... baseClasses) {}
static void NumerousStaticMethod(int i, BaseClasses&... baseClasses) {}
int InstanceMethod() { return 123; }
static int StaticMethod() { return 456; }
};
%}
%template (NumerousInherit0) NumerousInherit<>;
%template (NumerousInherit1) NumerousInherit<A>;
%template (NumerousInherit2) NumerousInherit<A,B>;
%template (NumerousInherit3) NumerousInherit<A,B,C>;
%inline %{
template <typename T, typename... BaseClasses> class LotsInherit : public T, public BaseClasses... {
public:
LotsInherit(T t, BaseClasses&... baseClasses) : BaseClasses(baseClasses)... {}
void LotsInstanceMethod(T t, BaseClasses&... baseClasses) {}
static void LotsStaticMethod(T t, BaseClasses&... baseClasses) {}
int InstanceMethod() { return 123; }
static int StaticMethod() { return 456; }
};
%}
%template (LotsInherit1) LotsInherit<A>;
%template (LotsInherit2) LotsInherit<A,B>;
%template (LotsInherit3) LotsInherit<A,B,C>;
%template (LotsInherit4) LotsInherit<A,B,C,D>;

View file

@ -0,0 +1,152 @@
from cpp11_variadic_templates import *
ma = MultiArgs1()
# SizeOf testing
so0 = SizeOf0()
if so0.size != 0:
raise RuntimeError("so0.size")
so1 = SizeOf1()
if so1.size != 1:
raise RuntimeError("so1.size")
so2 = SizeOf2()
if so2.size != 2:
raise RuntimeError("so2.size")
so3 = SizeOf3()
if so3.size != 3:
raise RuntimeError("so3.size")
a = A()
b = B()
c = C()
d = D()
# MultiInherit0
mi0 = MultiInherit0()
mi0.MultiInstanceMethod()
MultiInherit0.MultiStaticMethod()
mi0.InstanceMethod()
MultiInherit0.StaticMethod()
# MultiInherit1
mi1 = MultiInherit1(a)
if mi1.a != 100:
raise RuntimeError("fail mi1.a")
mi1.MultiInstanceMethod(a)
MultiInherit1.MultiStaticMethod(a)
mi1.InstanceMethod()
MultiInherit1.StaticMethod()
# MultiInherit2
mi2 = MultiInherit2(a, b)
if mi2.a != 100:
raise RuntimeError("fail mi2.a")
if mi2.b != 200:
raise RuntimeError("fail mi2.b")
mi2.MultiInstanceMethod(a, b)
MultiInherit2.MultiStaticMethod(a, b)
mi2.InstanceMethod()
MultiInherit2.StaticMethod()
# MultiInherit3
mi3 = MultiInherit3(a, b, c)
if mi3.a != 100:
raise RuntimeError("fail mi3.a")
if mi3.b != 200:
raise RuntimeError("fail mi3.b")
if mi3.c != 300:
raise RuntimeError("fail mi3.c")
mi3.MultiInstanceMethod(a, b, c)
MultiInherit3.MultiStaticMethod(a, b, c)
mi3.InstanceMethod()
MultiInherit3.StaticMethod()
# NumerousInherit0
num = 123
ni0 = NumerousInherit0(num)
ni0.NumerousInstanceMethod(num)
NumerousInherit0.NumerousStaticMethod(num)
ni0.InstanceMethod()
NumerousInherit0.StaticMethod()
# NumerousInherit1
ni1 = NumerousInherit1(num, a)
if ni1.a != 100:
raise RuntimeError("fail ni1.a")
ni1.NumerousInstanceMethod(num, a)
NumerousInherit1.NumerousStaticMethod(num, a)
ni1.InstanceMethod()
NumerousInherit1.StaticMethod()
# NumerousInherit2
ni2 = NumerousInherit2(num, a, b)
if ni2.a != 100:
raise RuntimeError("fail ni2.a")
if ni2.b != 200:
raise RuntimeError("fail ni2.b")
ni2.NumerousInstanceMethod(num, a, b)
NumerousInherit2.NumerousStaticMethod(num, a, b)
ni2.InstanceMethod()
NumerousInherit2.StaticMethod()
# NumerousInherit3
ni3 = NumerousInherit3(num, a, b, c)
if ni3.a != 100:
raise RuntimeError("fail ni3.a")
if ni3.b != 200:
raise RuntimeError("fail ni3.b")
if ni3.c != 300:
raise RuntimeError("fail ni3.c")
ni3.NumerousInstanceMethod(num, a, b, c)
NumerousInherit3.NumerousStaticMethod(num, a, b, c)
ni3.InstanceMethod()
NumerousInherit3.StaticMethod()
LotsInherit1
lots1 = LotsInherit1(a)
if lots1.a != 100:
raise RuntimeError("fail lots1.a")
lots1.LotsInstanceMethod(a)
LotsInherit1.LotsStaticMethod(a)
lots1.InstanceMethod()
LotsInherit1.StaticMethod()
# LotsInherit2
lots2 = LotsInherit2(a, b)
if lots2.a != 100:
raise RuntimeError("fail lots2.a")
if lots2.b != 200:
raise RuntimeError("fail lots2.b")
lots2.LotsInstanceMethod(a, b)
LotsInherit2.LotsStaticMethod(a, b)
lots2.InstanceMethod()
LotsInherit2.StaticMethod()
# LotsInherit3
lots3 = LotsInherit3(a, b, c)
if lots3.a != 100:
raise RuntimeError("fail lots3.a")
if lots3.b != 200:
raise RuntimeError("fail lots3.b")
if lots3.c != 300:
raise RuntimeError("fail lots3.c")
lots3.LotsInstanceMethod(a, b, c)
LotsInherit3.LotsStaticMethod(a, b, c)
lots3.InstanceMethod()
LotsInherit3.StaticMethod()
# LotsInherit4
lots4 = LotsInherit4(a, b, c, d)
if lots4.a != 100:
raise RuntimeError("fail lots4.a")
if lots4.b != 200:
raise RuntimeError("fail lots4.b")
if lots4.c != 300:
raise RuntimeError("fail lots4.c")
if lots4.d != 400:
raise RuntimeError("fail lots4.c")
lots4.LotsInstanceMethod(a, b, c, d)
LotsInherit4.LotsStaticMethod(a, b, c, d)
lots4.InstanceMethod()
LotsInherit4.StaticMethod()

View file

@ -2879,7 +2879,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
Parm *tparms = Getattr(nn,"templateparms"); Parm *tparms = Getattr(nn,"templateparms");
if (!tparms) { if (!tparms) {
specialized = 1; specialized = 1;
} else if (Getattr(tparms,"variadic") && strncmp(Char(Getattr(tparms,"variadic")), "1", 1)==0) { } else if (ParmList_variadic_parm(tparms)) {
variadic = 1; variadic = 1;
} }
if (nnisclass && !variadic && !specialized && (ParmList_len($7) > ParmList_len(tparms))) { if (nnisclass && !variadic && !specialized && (ParmList_len($7) > ParmList_len(tparms))) {
@ -4429,12 +4429,12 @@ templateparameter : templcpptype def_args {
const char *t = Strchr(type, ' '); const char *t = Strchr(type, ' ');
Setattr(p, "name", t + 1); Setattr(p, "name", t + 1);
Setattr(p, "type", NewStringWithSize(type, t - Char(type))); Setattr(p, "type", NewStringWithSize(type, t - Char(type)));
} else if ((Strncmp(type, "class... ", 9) == 0) || (Strncmp(type, "typename... ", 12) == 0)) { } else if ((Strncmp(type, "v.class ", 8) == 0) || (Strncmp(type, "v.typename ", 11) == 0)) {
/* Variadic template args */ /* Variadic template args */
const char *t = Strchr(type, ' '); const char *t = Strchr(type, ' ');
Setattr(p, "name", t + 1); Setattr(p, "name", t + 1);
Setattr(p, "type", NewStringWithSize(type, t - Char(type))); Setattr(p, "type", NewStringWithSize(type, t - Char(type)));
Setattr(p, "variadic", "1"); SetFlag(p, "variadic");
} }
} }
} }
@ -5540,6 +5540,8 @@ declarator : pointer notso_direct_declarator {
$$ = $3; $$ = $3;
$$.type = NewStringEmpty(); $$.type = NewStringEmpty();
SwigType_add_reference($$.type); SwigType_add_reference($$.type);
SwigType_add_variadic($$.type);
/* TODO: add other SwigType_add_variadic */
if ($3.type) { if ($3.type) {
SwigType_push($$.type,$3.type); SwigType_push($$.type,$3.type);
Delete($3.type); Delete($3.type);
@ -6923,8 +6925,11 @@ base_specifier : opt_virtual {
} else { } else {
Setattr($$,"access","public"); Setattr($$,"access","public");
} }
if ($4) if ($4) {
/*TODO: remove "variadic" flag */
SetFlag($$, "variadic"); SetFlag($$, "variadic");
SwigType_add_variadic(Getattr($$, "name"));
}
} }
| opt_virtual access_specifier { | opt_virtual access_specifier {
$<intvalue>$ = cparse_line; $<intvalue>$ = cparse_line;
@ -6939,8 +6944,10 @@ base_specifier : opt_virtual {
if (Strcmp($2,"public") != 0) { if (Strcmp($2,"public") != 0) {
Swig_warning(WARN_PARSE_PRIVATE_INHERIT, Getfile($$), Getline($$), "%s inheritance from base '%s' (ignored).\n", $2, SwigType_namestr($5)); Swig_warning(WARN_PARSE_PRIVATE_INHERIT, Getfile($$), Getline($$), "%s inheritance from base '%s' (ignored).\n", $2, SwigType_namestr($5));
} }
if ($6) if ($6) {
SetFlag($$, "variadic"); SetFlag($$, "variadic");
SwigType_add_variadic(Getattr($$, "name"));
}
} }
; ;
@ -6958,11 +6965,13 @@ templcpptype : CLASS {
if (!inherit_list) last_cpptype = $$; if (!inherit_list) last_cpptype = $$;
} }
| CLASS ELLIPSIS { | CLASS ELLIPSIS {
$$ = (char *)"class..."; /* TODO: call SwigType_add_variadic() instead */
$$ = (char *)"v.class";
if (!inherit_list) last_cpptype = $$; if (!inherit_list) last_cpptype = $$;
} }
| TYPENAME ELLIPSIS { | TYPENAME ELLIPSIS {
$$ = (char *)"typename..."; /* TODO: call SwigType_add_variadic() instead */
$$ = (char *)"v.typename";
if (!inherit_list) last_cpptype = $$; if (!inherit_list) last_cpptype = $$;
} }
; ;

View file

@ -26,6 +26,13 @@ void SwigType_template_init(void) {
} }
/* -----------------------------------------------------------------------------
* add_parms()
*
* Add the value and type of each parameter into patchlist and typelist
* (List of String/SwigType) for later template parameter substitutions.
* ----------------------------------------------------------------------------- */
static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_pattern) { static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_pattern) {
while (p) { while (p) {
SwigType *ty = Getattr(p, "type"); SwigType *ty = Getattr(p, "type");
@ -44,6 +51,58 @@ static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_patte
} }
} }
/* -----------------------------------------------------------------------------
* expand_variadic_parms()
*
* Expand variadic parameter in the parameter list stored as attribute in n. For example:
* template <typename... T> struct X : { X(T&... tt); }
* %template(XABC) X<A,B,C>;
* inputs for the constructor parameter list will be for attribute = "parms":
* Getattr(n, attribute) : v.r.T tt
* unexpanded_variadic_parm: v.typename T
* expanded_variadic_parms : A,B,C
* results in:
* Getattr(n, attribute) : r.A,r.B,r.C
* that is, template is expanded as: struct XABC : { X(A&,B&,C&); }
* Note that there are no parameter names are in the expanded parameter list.
* Nothing happens if the parameter list has no variadic parameters.
* ----------------------------------------------------------------------------- */
static void expand_variadic_parms(Node *n, const char *attribute, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms) {
ParmList *p = Getattr(n, attribute);
Parm *variadic = ParmList_variadic_parm(p);
if (variadic) {
if (unexpanded_variadic_parm) {
SwigType *type = Getattr(variadic, "type");
String *unexpanded_name = Getattr(unexpanded_variadic_parm, "name");
ParmList *expanded = CopyParmList(expanded_variadic_parms);
Parm *ep = expanded;
while (ep) {
SwigType *newtype = Copy(type);
SwigType_del_variadic(newtype);
Replaceid(newtype, unexpanded_name, Getattr(ep, "type"));
Setattr(ep, "type", newtype);
ep = nextSibling(ep);
}
expanded = ParmList_replace_last(p, expanded);
Setattr(n, attribute, expanded);
}
}
}
/* -----------------------------------------------------------------------------
* expand_parms()
*
* Expand variadic parameters in parameter lists and add parameters to patchlist
* and typelist for later template parameter substitutions.
* ----------------------------------------------------------------------------- */
static void expand_parms(Node *n, const char *attribute, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms, List *patchlist, List *typelist, int is_pattern) {
ParmList *p;
expand_variadic_parms(n, attribute, unexpanded_variadic_parm, expanded_variadic_parms);
p = Getattr(n, attribute);
add_parms(p, patchlist, typelist, is_pattern);
}
void Swig_cparse_debug_templates(int x) { void Swig_cparse_debug_templates(int x) {
template_debug = x; template_debug = x;
} }
@ -56,7 +115,7 @@ void Swig_cparse_debug_templates(int x) {
* template parameters * template parameters
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
static void cparse_template_expand(Node *templnode, Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) { static void cparse_template_expand(Node *templnode, Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms) {
static int expanded = 0; static int expanded = 0;
String *nodeType; String *nodeType;
if (!n) if (!n)
@ -70,7 +129,7 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
if (!expanded) { if (!expanded) {
expanded = 1; expanded = 1;
set_nodeType(n, Getattr(n, "templatetype")); set_nodeType(n, Getattr(n, "templatetype"));
cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist, unexpanded_variadic_parm, expanded_variadic_parms);
expanded = 0; expanded = 0;
return; return;
} else { } else {
@ -78,7 +137,7 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
/* Member templates */ /* Member templates */
set_nodeType(n, Getattr(n, "templatetype")); set_nodeType(n, Getattr(n, "templatetype"));
cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist, unexpanded_variadic_parm, expanded_variadic_parms);
set_nodeType(n, "template"); set_nodeType(n, "template");
return; return;
} }
@ -113,8 +172,8 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
Append(typelist, Getattr(n, "name")); Append(typelist, Getattr(n, "name"));
} }
add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); expand_parms(n, "parms", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); expand_parms(n, "throws", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
} else if (Equal(nodeType, "class")) { } else if (Equal(nodeType, "class")) {
/* Patch base classes */ /* Patch base classes */
@ -127,8 +186,27 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
int ilen = Len(bases); int ilen = Len(bases);
for (i = 0; i < ilen; i++) { for (i = 0; i < ilen; i++) {
String *name = Copy(Getitem(bases, i)); String *name = Copy(Getitem(bases, i));
Setitem(bases, i, name); if (SwigType_isvariadic(name)) {
Append(typelist, name); Parm *parm = NewParmWithoutFileLineInfo(name, 0);
Node *temp_parm_node = NewHash();
Setattr(temp_parm_node, "variadicbaseparms", parm);
assert(i == ilen - 1);
Delitem(bases, i);
expand_variadic_parms(temp_parm_node, "variadicbaseparms", unexpanded_variadic_parm, expanded_variadic_parms);
{
Parm *vp = Getattr(temp_parm_node, "variadicbaseparms");
while (vp) {
String *name = Copy(Getattr(vp, "type"));
Append(bases, name);
Append(typelist, name);
vp = nextSibling(vp);
}
}
Delete(temp_parm_node);
} else {
Setitem(bases, i, name);
Append(typelist, name);
}
} }
} }
} }
@ -137,7 +215,7 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
{ {
Node *cn = firstChild(n); Node *cn = firstChild(n);
while (cn) { while (cn) {
cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist, unexpanded_variadic_parm, expanded_variadic_parms);
cn = nextSibling(cn); cn = nextSibling(cn);
} }
} }
@ -180,8 +258,8 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
} }
Append(cpatchlist, Getattr(n, "code")); Append(cpatchlist, Getattr(n, "code"));
Append(typelist, Getattr(n, "decl")); Append(typelist, Getattr(n, "decl"));
add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); expand_parms(n, "parms", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); expand_parms(n, "throws", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
} else if (Equal(nodeType, "destructor")) { } else if (Equal(nodeType, "destructor")) {
/* We only need to patch the dtor of the template itself, not the destructors of any nested classes, so check that the parent of this node is the root /* We only need to patch the dtor of the template itself, not the destructors of any nested classes, so check that the parent of this node is the root
* template node, with the special exception for %extend which adds its methods under an intermediate node. */ * template node, with the special exception for %extend which adds its methods under an intermediate node. */
@ -222,13 +300,13 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
Append(cpatchlist, Getattr(n, "code")); Append(cpatchlist, Getattr(n, "code"));
Append(typelist, Getattr(n, "type")); Append(typelist, Getattr(n, "type"));
Append(typelist, Getattr(n, "decl")); Append(typelist, Getattr(n, "decl"));
add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); expand_parms(n, "parms", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
add_parms(Getattr(n, "kwargs"), cpatchlist, typelist, 0); expand_parms(n, "kwargs", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
add_parms(Getattr(n, "pattern"), cpatchlist, typelist, 1); expand_parms(n, "pattern", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 1);
add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); expand_parms(n, "throws", unexpanded_variadic_parm, expanded_variadic_parms, cpatchlist, typelist, 0);
cn = firstChild(n); cn = firstChild(n);
while (cn) { while (cn) {
cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist, unexpanded_variadic_parm, expanded_variadic_parms);
cn = nextSibling(cn); cn = nextSibling(cn);
} }
} }
@ -351,18 +429,14 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
String *tname; String *tname;
String *iname; String *iname;
String *tbase; String *tbase;
Parm *unexpanded_variadic_parm = 0;
ParmList *expanded_variadic_parms = 0;
patchlist = NewList(); patchlist = NewList();
cpatchlist = NewList(); cpatchlist = NewList();
typelist = NewList(); typelist = NewList();
{ templateargs = NewStringEmpty();
String *tmp = NewStringEmpty(); SwigType_add_template(templateargs, tparms);
if (tparms) {
SwigType_add_template(tmp, tparms);
}
templateargs = Copy(tmp);
Delete(tmp);
}
tname = Copy(Getattr(n, "name")); tname = Copy(Getattr(n, "name"));
tbase = Swig_scopename_last(tname); tbase = Swig_scopename_last(tname);
@ -400,10 +474,15 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
} }
*/ */
ParmList *templateparms = Getattr(n, "templateparms");
unexpanded_variadic_parm = ParmList_variadic_parm(templateparms);
if (unexpanded_variadic_parm)
expanded_variadic_parms = ParmList_nth_parm(tparms, ParmList_len(templateparms) - 1);
/* Printf(stdout,"targs = '%s'\n", templateargs); /* Printf(stdout,"targs = '%s'\n", templateargs);
Printf(stdout,"rname = '%s'\n", rname); Printf(stdout,"rname = '%s'\n", rname);
Printf(stdout,"tname = '%s'\n", tname); */ Printf(stdout,"tname = '%s'\n", tname); */
cparse_template_expand(n, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); cparse_template_expand(n, n, tname, rname, templateargs, patchlist, typelist, cpatchlist, unexpanded_variadic_parm, expanded_variadic_parms);
/* Set the name */ /* Set the name */
{ {
@ -472,6 +551,9 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
*/ */
Node * tynode = Swig_symbol_clookup(s, 0); Node * tynode = Swig_symbol_clookup(s, 0);
String *tyname = tynode ? Getattr(tynode, "sym:name") : 0; String *tyname = tynode ? Getattr(tynode, "sym:name") : 0;
/*
Printf(stdout, " replacing %s with %s to %s or %s to %s\n", s, name, dvalue, tbase, iname);
*/
if (!tyname || !tsname || !Equal(tyname, tsname) || Getattr(tynode, "templatetype")) { if (!tyname || !tsname || !Equal(tyname, tsname) || Getattr(tynode, "templatetype")) {
SwigType_typename_replace(s, name, dvalue); SwigType_typename_replace(s, name, dvalue);
SwigType_typename_replace(s, tbase, iname); SwigType_typename_replace(s, tbase, iname);
@ -1015,9 +1097,11 @@ Node *Swig_cparse_template_locate(String *name, Parm *tparms, String *symname, S
* Grab the parameter names from templateparms. * Grab the parameter names from templateparms.
* Non-type template parameters have no type information in expanded_templateparms. * Non-type template parameters have no type information in expanded_templateparms.
* Grab them from templateparms. * Grab them from templateparms.
*
* Return 1 if there are variadic template parameters, 0 otherwise.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
static void merge_parameters(ParmList *expanded_templateparms, ParmList *templateparms) { static int merge_parameters(ParmList *expanded_templateparms, ParmList *templateparms) {
Parm *p = expanded_templateparms; Parm *p = expanded_templateparms;
Parm *tp = templateparms; Parm *tp = templateparms;
while (p && tp) { while (p && tp) {
@ -1027,6 +1111,7 @@ static void merge_parameters(ParmList *expanded_templateparms, ParmList *templat
p = nextSibling(p); p = nextSibling(p);
tp = nextSibling(tp); tp = nextSibling(tp);
} }
return ParmList_variadic_parm(templateparms) ? 1 : 0;
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
@ -1088,14 +1173,16 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, N
if (Equal(Getattr(primary, "templatetype"), "class")) { if (Equal(Getattr(primary, "templatetype"), "class")) {
/* Templated class */ /* Templated class */
expanded_templateparms = CopyParmList(instantiated_parameters); expanded_templateparms = CopyParmList(instantiated_parameters);
merge_parameters(expanded_templateparms, templateparms); int variadic = merge_parameters(expanded_templateparms, templateparms);
/* Add default arguments from chosen template */ /* Add default arguments from primary template */
ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parameters)); if (!variadic) {
if (defaults_start) { ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parameters));
ParmList *defaults = CopyParmList(defaults_start); if (defaults_start) {
mark_defaults(defaults); ParmList *defaults = CopyParmList(defaults_start);
expanded_templateparms = ParmList_join(expanded_templateparms, defaults); mark_defaults(defaults);
expand_defaults(expanded_templateparms); expanded_templateparms = ParmList_join(expanded_templateparms, defaults);
expand_defaults(expanded_templateparms);
}
} }
} else { } else {
/* Templated function */ /* Templated function */
@ -1104,11 +1191,5 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, N
merge_parameters(expanded_templateparms, templateparms); merge_parameters(expanded_templateparms, templateparms);
} }
if (templateparms && (ParmList_len(templateparms) < ParmList_len(expanded_templateparms))) {
SWIG_WARN_NODE_BEGIN(nn);
Swig_warning(WARN_CPP11_VARIADIC_TEMPLATE, cparse_file, cparse_line, "Only the first variadic template argument is currently supported.\n");
SWIG_WARN_NODE_END(nn);
}
return expanded_templateparms; return expanded_templateparms;
} }

View file

@ -98,7 +98,7 @@
#define WARN_CPP11_LAMBDA 340 #define WARN_CPP11_LAMBDA 340
#define WARN_CPP11_ALIAS_DECLARATION 341 /* redundant now */ #define WARN_CPP11_ALIAS_DECLARATION 341 /* redundant now */
#define WARN_CPP11_ALIAS_TEMPLATE 342 /* redundant now */ #define WARN_CPP11_ALIAS_TEMPLATE 342 /* redundant now */
#define WARN_CPP11_VARIADIC_TEMPLATE 343 #define WARN_CPP11_VARIADIC_TEMPLATE 343 /* redundant now */
#define WARN_CPP11_DECLTYPE 344 #define WARN_CPP11_DECLTYPE 344
#define WARN_IGNORE_OPERATOR_NEW 350 /* new */ #define WARN_IGNORE_OPERATOR_NEW 350 /* new */

View file

@ -122,11 +122,10 @@ ParmList *CopyParmList(ParmList *p) {
ParmList *ParmList_join(ParmList *p, ParmList *p2) { ParmList *ParmList_join(ParmList *p, ParmList *p2) {
Parm *firstparm = p ? p : p2; Parm *firstparm = p ? p : p2;
Parm *lastparm = p; Parm *lastparm = 0;
while (p) { while (p) {
lastparm = p;
p = nextSibling(p); p = nextSibling(p);
if (p)
lastparm = p;
} }
if (lastparm) if (lastparm)
set_nextSibling(lastparm, p2); set_nextSibling(lastparm, p2);
@ -134,22 +133,60 @@ ParmList *ParmList_join(ParmList *p, ParmList *p2) {
return firstparm; return firstparm;
} }
/* -----------------------------------------------------------------------------
* ParmList_replace_last()
*
* Delete last parameter in p and replace it with parameter list p2.
* p must have at least one element, that is, must not be NULL.
* Return beginning of modified parameter list.
* ----------------------------------------------------------------------------- */
ParmList *ParmList_replace_last(ParmList *p, ParmList *p2) {
ParmList *start = p;
int len = ParmList_len(p);
assert(p);
if (len == 1) {
start = p2;
} else if (len > 1) {
Parm *secondlastparm = ParmList_nth_parm(p, len - 2);
set_nextSibling(secondlastparm, p2);
}
return start;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* ParmList_nth_parm() * ParmList_nth_parm()
* *
* return the nth parameter (0 based) in the parameter list * return the nth parameter (0 based) in the parameter list
* return NULL if there are not enough parameters in the list
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
Parm *ParmList_nth_parm(ParmList *p, unsigned int n) { Parm *ParmList_nth_parm(ParmList *p, unsigned int n) {
while (p) { while (p) {
if (n == 0) if (n == 0) {
break; break;
}
n--; n--;
p = nextSibling(p); p = nextSibling(p);
} }
return p; return p;
} }
/* -----------------------------------------------------------------------------
* ParmList_variadic_parm()
*
* Return the variadic parm (last in list if it is variadic), NULL otherwise
* ----------------------------------------------------------------------------- */
Parm *ParmList_variadic_parm(ParmList *p) {
Parm *lastparm = 0;
while (p) {
lastparm = p;
p = nextSibling(p);
}
return lastparm && SwigType_isvariadic(Getattr(lastparm, "type")) ? lastparm : 0;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* ParmList_numrequired() * ParmList_numrequired()
* *
@ -303,10 +340,10 @@ int ParmList_has_defaultargs(ParmList *p) {
* ---------------------------------------------------------------------- */ * ---------------------------------------------------------------------- */
int ParmList_has_varargs(ParmList *p) { int ParmList_has_varargs(ParmList *p) {
Parm *lp = 0; Parm *lastparm = 0;
while (p) { while (p) {
lp = p; lastparm = p;
p = nextSibling(p); p = nextSibling(p);
} }
return lp ? SwigType_isvarargs(Getattr(lp, "type")) : 0; return lastparm ? SwigType_isvarargs(Getattr(lastparm, "type")) : 0;
} }

View file

@ -42,6 +42,7 @@
* 'p.' = Pointer (*) * 'p.' = Pointer (*)
* 'r.' = Reference (&) * 'r.' = Reference (&)
* 'z.' = Rvalue reference (&&) * 'z.' = Rvalue reference (&&)
* 'v.' = Variadic (...)
* 'a(n).' = Array of size n [n] * 'a(n).' = Array of size n [n]
* 'f(..,..).' = Function with arguments (args) * 'f(..,..).' = Function with arguments (args)
* 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier)
@ -624,6 +625,12 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
Insert(result, 0, "("); Insert(result, 0, "(");
Append(result, ")"); Append(result, ")");
} }
} else if (SwigType_isvariadic(element)) {
Insert(result, 0, "...");
if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
Insert(result, 0, "(");
Append(result, ")");
}
} else if (SwigType_isarray(element)) { } else if (SwigType_isarray(element)) {
DOH *size; DOH *size;
Append(result, "["); Append(result, "[");

View file

@ -129,6 +129,8 @@ extern "C" {
extern SwigType *SwigType_del_reference(SwigType *t); extern SwigType *SwigType_del_reference(SwigType *t);
extern SwigType *SwigType_add_rvalue_reference(SwigType *t); extern SwigType *SwigType_add_rvalue_reference(SwigType *t);
extern SwigType *SwigType_del_rvalue_reference(SwigType *t); extern SwigType *SwigType_del_rvalue_reference(SwigType *t);
extern SwigType *SwigType_add_variadic(SwigType *t);
extern SwigType *SwigType_del_variadic(SwigType *t);
extern SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual); extern SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual);
extern SwigType *SwigType_del_qualifier(SwigType *t); extern SwigType *SwigType_del_qualifier(SwigType *t);
extern SwigType *SwigType_add_function(SwigType *t, ParmList *parms); extern SwigType *SwigType_add_function(SwigType *t, ParmList *parms);
@ -155,6 +157,7 @@ extern "C" {
extern int SwigType_isreference(const SwigType *t); extern int SwigType_isreference(const SwigType *t);
extern int SwigType_isreference_return(const SwigType *t); extern int SwigType_isreference_return(const SwigType *t);
extern int SwigType_isrvalue_reference(const SwigType *t); extern int SwigType_isrvalue_reference(const SwigType *t);
extern int SwigType_isvariadic(const SwigType *t);
extern int SwigType_isarray(const SwigType *t); extern int SwigType_isarray(const SwigType *t);
extern int SwigType_prefix_is_simple_1D_array(const SwigType *t); extern int SwigType_prefix_is_simple_1D_array(const SwigType *t);
extern int SwigType_isfunction(const SwigType *t); extern int SwigType_isfunction(const SwigType *t);

View file

@ -22,7 +22,10 @@ extern Parm *CopyParm(Parm *p);
extern ParmList *CopyParmList(ParmList *p); extern ParmList *CopyParmList(ParmList *p);
extern ParmList *CopyParmListMax(ParmList *p, int count); extern ParmList *CopyParmListMax(ParmList *p, int count);
extern ParmList *ParmList_join(ParmList *p, ParmList *p2); extern ParmList *ParmList_join(ParmList *p, ParmList *p2);
extern Parm *ParmList_nth_parm(ParmList *p, unsigned int n); extern ParmList *ParmList_replace_last(ParmList *p, ParmList *p2);
extern Parm *ParmList_nth_parm(ParmList *p, unsigned int n);
extern Parm *ParmList_variadic_parm(ParmList *p);
extern Parm *ParmList_add_parm(ParmList *p, Parm *newparm);
extern int ParmList_numrequired(ParmList *); extern int ParmList_numrequired(ParmList *);
extern int ParmList_len(ParmList *); extern int ParmList_len(ParmList *);
extern int ParmList_has_defaultargs(ParmList *p); extern int ParmList_has_defaultargs(ParmList *p);

View file

@ -114,6 +114,10 @@ void Swig_print_node(Node *obj) {
} }
Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc); Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc);
Delete(o); Delete(o);
/*
} else if (DohIsSequence(value)) {
Printf(stdout, "%-12s - %s\n", k, value);
*/
} else { } else {
Printf(stdout, "%-12s - %p\n", k, value); Printf(stdout, "%-12s - %p\n", k, value);
} }

View file

@ -45,6 +45,7 @@
* 'p.' = Pointer (*) * 'p.' = Pointer (*)
* 'r.' = Reference or ref-qualifier (&) * 'r.' = Reference or ref-qualifier (&)
* 'z.' = Rvalue reference or ref-qualifier (&&) * 'z.' = Rvalue reference or ref-qualifier (&&)
* 'v.' = Variadic (...)
* 'a(n).' = Array of size n [n] * 'a(n).' = Array of size n [n]
* 'f(..,..).' = Function with arguments (args) * 'f(..,..).' = Function with arguments (args)
* 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier)
@ -79,6 +80,7 @@
* SwigType_add_pointer() * SwigType_add_pointer()
* SwigType_add_reference() * SwigType_add_reference()
* SwigType_add_rvalue_reference() * SwigType_add_rvalue_reference()
* SwigType_add_variadic()
* SwigType_add_array() * SwigType_add_array()
* *
* These are used to build new types. There are also functions to undo these * These are used to build new types. There are also functions to undo these
@ -87,6 +89,7 @@
* SwigType_del_pointer() * SwigType_del_pointer()
* SwigType_del_reference() * SwigType_del_reference()
* SwigType_del_rvalue_reference() * SwigType_del_rvalue_reference()
* SwigType_del_variadic()
* SwigType_del_array() * SwigType_del_array()
* *
* In addition, there are query functions * In addition, there are query functions
@ -94,6 +97,7 @@
* SwigType_ispointer() * SwigType_ispointer()
* SwigType_isreference() * SwigType_isreference()
* SwigType_isrvalue_reference() * SwigType_isrvalue_reference()
* SwigType_isvariadic()
* SwigType_isarray() * SwigType_isarray()
* *
* Finally, there are some data extraction functions that can be used to * Finally, there are some data extraction functions that can be used to
@ -499,6 +503,43 @@ int SwigType_isrvalue_reference(const SwigType *t) {
return 0; return 0;
} }
/* -----------------------------------------------------------------------------
* Variadic
*
* SwigType_add_variadic()
* SwigType_del_variadic()
* SwigType_isvariadic()
*
* Add, remove, and test if a type is a variadic. The deletion and query
* functions take into account qualifiers (if any).
* ----------------------------------------------------------------------------- */
SwigType *SwigType_add_variadic(SwigType *t) {
Insert(t, 0, "v.");
return t;
}
SwigType *SwigType_del_variadic(SwigType *t) {
char *c = Char(t);
if (strncmp(c, "v.", 2)) {
printf("Fatal error: SwigType_del_variadic applied to non-variadic.\n");
Exit(EXIT_FAILURE);
}
Delslice(t, 0, 2);
return t;
}
int SwigType_isvariadic(const SwigType *t) {
char *c;
if (!t)
return 0;
c = Char(t);
if (strncmp(c, "v.", 2) == 0) {
return 1;
}
return 0;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Qualifiers * Qualifiers
* *