Fix instantiation of variadic class templates

containing parameter pack arguments that are function pointers.

  template <typename... V> struct VariadicParms {
    void ParmsFuncPtrVal(int (*)(V...)) {}
  };

  %template(VariadicParms0) VariadicParms<>;
  %template(VariadicParms1) VariadicParms<A>;
This commit is contained in:
William S Fulton 2022-12-27 19:36:40 +00:00
commit 674abaddbf
6 changed files with 162 additions and 30 deletions

View file

@ -7,8 +7,19 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress) Version 4.2.0 (in progress)
=========================== ===========================
2022-12-27: wsfulton
Fix instantiation of variadic class templates containing parameter pack arguments that
are function pointers.
template <typename... V> struct VariadicParms {
void ParmsFuncPtrVal(int (*)(V...)) {}
};
%template(VariadicParms0) VariadicParms<>;
%template(VariadicParms1) VariadicParms<A>;
2022-12-23: wsfulton 2022-12-23: wsfulton
#1863 Fix syntax error parsing variadic template parameter pack arguments that #1863 Fix syntax error parsing variadic templates containing parameter pack arguments that
are function pointers. are function pointers.
2022-12-22: wsfulton 2022-12-22: wsfulton

View file

@ -139,8 +139,13 @@ public:
%template (LotsInherit3) LotsInherit<A,B,C>; %template (LotsInherit3) LotsInherit<A,B,C>;
%template (LotsInherit4) LotsInherit<A,B,C,D>; %template (LotsInherit4) LotsInherit<A,B,C,D>;
%inline %{ %inline %{
struct KlassMemFuncs {
int memfunc0() { return 0; }
int memfunc1() { return 1; }
int memfunc2() { return 2; }
int memfunc3() { return 3; }
};
template <typename... V> struct VariadicParms { template <typename... V> struct VariadicParms {
public: public:
void ParmsVal(V... vparms_v) {} void ParmsVal(V... vparms_v) {}
@ -151,15 +156,39 @@ public:
void ParmsRValueRef(V&&... vparms_r) {} void ParmsRValueRef(V&&... vparms_r) {}
void ParmsConstRef(const V&... vparms_cr) {} void ParmsConstRef(const V&... vparms_cr) {}
void ParmsFuncPtrVal(int (*)(V...)) {}
void ParmsMemFuncPtrVal(int (KlassMemFuncs::*)(V...)) {}
// TODO // TODO
// void ParmsFuncPtr(int (*)(V...)) {} // void ParmsFuncPtrRef(int (*)(V&...)) {}
}; };
%} %}
%template(VariadicParms0) VariadicParms<>;
%template(VariadicParms1) VariadicParms<A>; %template(VariadicParms1) VariadicParms<A>;
%template(VariadicParms2) VariadicParms<A,B>; %template(VariadicParms2) VariadicParms<A,B>;
%template(VariadicParms3) VariadicParms<A,B,C>; %template(VariadicParms3) VariadicParms<A,B,C>;
%inline %{
template <typename... V> struct FixedAndVariadicParms {
public:
void ParmsVal(short shortvar, V... vparms_v) {}
void ParmsPtr(short shortvar, V*... vparms_p) {}
void ParmsPtrRef(short shortvar, V*&... vparms_pr) {}
void ParmsPtrRValueRef(short shortvar, V*&&... vparms_rvr) {}
void ParmsRef(short shortvar, V&... vparms_r) {}
void ParmsRValueRef(short shortvar, V&&... vparms_r) {}
void ParmsConstRef(short shortvar, const V&... vparms_cr) {}
void ParmsFuncPtrVal(short shortvar, int (*)(short, V...)) {}
void ParmsMemFuncPtrVal(int (KlassMemFuncs::*)(V...)) {}
};
%}
%template(FixedAndVariadicParms0) FixedAndVariadicParms<>;
%template(FixedAndVariadicParms1) FixedAndVariadicParms<A>;
%template(FixedAndVariadicParms2) FixedAndVariadicParms<A,B>;
%template(FixedAndVariadicParms3) FixedAndVariadicParms<A,B,C>;
// #1863 // #1863
%inline %{ %inline %{
@ -167,11 +196,13 @@ class Container {
public: public:
template<typename... Args> template<typename... Args>
static void notifyMyTypes(void (fn)(Args...)); static void notifyMyTypes(void (fn)(Args...));
//static void notifyMyTypes(void (*fn)(Args...));
}; };
%} %}
%{ %{
template<typename... Args> template<typename... Args>
void Container::notifyMyTypes(void (fn)(Args...)) {} void Container::notifyMyTypes(void (fn)(Args...)) {}
// void Container::notifyMyTypes(void (*fn)(Args...)) {}
// Explicit template instantiations // Explicit template instantiations
template void Container::notifyMyTypes<>(void (tt)()); template void Container::notifyMyTypes<>(void (tt)());

View file

@ -25,6 +25,9 @@ void SwigType_template_init(void) {
baselists[2] = "privatebaselist"; baselists[2] = "privatebaselist";
} }
void Swig_cparse_debug_templates(int x) {
template_debug = x;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* add_parms() * add_parms()
@ -70,9 +73,9 @@ static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_patte
static void expand_variadic_parms(Node *n, const char *attribute, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms) { static void expand_variadic_parms(Node *n, const char *attribute, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms) {
ParmList *p = Getattr(n, attribute); ParmList *p = Getattr(n, attribute);
Parm *variadic = ParmList_variadic_parm(p); if (unexpanded_variadic_parm) {
if (variadic) { Parm *variadic = ParmList_variadic_parm(p);
if (unexpanded_variadic_parm) { if (variadic) {
SwigType *type = Getattr(variadic, "type"); SwigType *type = Getattr(variadic, "type");
String *unexpanded_name = Getattr(unexpanded_variadic_parm, "name"); String *unexpanded_name = Getattr(unexpanded_variadic_parm, "name");
ParmList *expanded = CopyParmList(expanded_variadic_parms); ParmList *expanded = CopyParmList(expanded_variadic_parms);
@ -103,9 +106,6 @@ static void expand_parms(Node *n, const char *attribute, Parm *unexpanded_variad
p = Getattr(n, attribute); p = Getattr(n, attribute);
add_parms(p, patchlist, typelist, is_pattern); add_parms(p, patchlist, typelist, is_pattern);
} }
void Swig_cparse_debug_templates(int x) {
template_debug = x;
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* cparse_template_expand() * cparse_template_expand()
@ -254,7 +254,6 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
Delete(tmp); Delete(tmp);
} }
} }
/* Setattr(n,"sym:name",name); */
} }
Append(cpatchlist, Getattr(n, "code")); Append(cpatchlist, Getattr(n, "code"));
Append(typelist, Getattr(n, "decl")); Append(typelist, Getattr(n, "decl"));
@ -282,7 +281,6 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
Replace(name, tname, rname, DOH_REPLACE_ANY); Replace(name, tname, rname, DOH_REPLACE_ANY);
} }
} }
/* Setattr(n,"sym:name",name); */
Append(cpatchlist, Getattr(n, "code")); Append(cpatchlist, Getattr(n, "code"));
} }
} else if (Equal(nodeType, "using")) { } else if (Equal(nodeType, "using")) {
@ -431,9 +429,9 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
String *tbase; String *tbase;
Parm *unexpanded_variadic_parm = 0; Parm *unexpanded_variadic_parm = 0;
ParmList *expanded_variadic_parms = 0; ParmList *expanded_variadic_parms = 0;
patchlist = NewList(); patchlist = NewList(); /* List of String * ("name" and "value" attributes) */
cpatchlist = NewList(); cpatchlist = NewList(); /* List of String * (code) */
typelist = NewList(); typelist = NewList(); /* List of SwigType * types */
templateargs = NewStringEmpty(); templateargs = NewStringEmpty();
SwigType_add_template(templateargs, tparms); SwigType_add_template(templateargs, tparms);
@ -499,7 +497,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
Parm *p = tparms; Parm *p = tparms;
/* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */
if (tp) { if (p && tp) {
Symtab *tsdecl = Getattr(n, "sym:symtab"); Symtab *tsdecl = Getattr(n, "sym:symtab");
String *tsname = Getattr(n, "sym:name"); String *tsname = Getattr(n, "sym:name");
while (p && tp) { while (p && tp) {
@ -542,17 +540,22 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
} }
sz = Len(typelist); sz = Len(typelist);
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
String *s = Getitem(typelist, i); SwigType *s = Getitem(typelist, i);
assert(!SwigType_isvariadic(s)); /* All parameters should have already been expanded, this is for function that contain variadic parameters only, such as f(v.p.V) */
SwigType_variadic_replace(s, unexpanded_variadic_parm, expanded_variadic_parms);
/* /*
The approach of 'trivially' replacing template arguments is kind of fragile. The approach of 'trivially' replacing template arguments is kind of fragile.
In particular if types with similar name in different namespaces appear. In particular if types with similar name in different namespaces appear.
We will not replace template args if a type/class exists with the same We will not replace template args if a type/class exists with the same
name which is not a template. name which is not a template.
*/ */
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); Printf(stdout, " replacing %s with %s to %s or %s to %s\n", s, name, dvalue, tbase, iname);
Printf(stdout, " %d %s to %s\n", tp == unexpanded_variadic_parm, name, ParmList_str_defaultargs(expanded_variadic_parms));
*/ */
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);
@ -586,6 +589,8 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
sz = Len(typelist); sz = Len(typelist);
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
String *s = Getitem(typelist, i); String *s = Getitem(typelist, i);
assert(!SwigType_isvariadic(s)); /* All parameters should have already been expanded, this is for function that contain variadic parameters only, such as f(v.p.V) */
SwigType_variadic_replace(s, unexpanded_variadic_parm, expanded_variadic_parms);
SwigType_typename_replace(s, tbase, iname); SwigType_typename_replace(s, tbase, iname);
} }
} }

View file

@ -1392,6 +1392,72 @@ void SwigType_typename_replace(SwigType *t, String *pat, String *rep) {
Delete(elem); Delete(elem);
} }
/* -----------------------------------------------------------------------------
* SwigType_variadic_replace()
*
* Replaces variadic parameter with a list of (zero or more) parameters.
* Needed for variadic templates.
* ----------------------------------------------------------------------------- */
void SwigType_variadic_replace(SwigType *t, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms) {
String *nt;
int i, ilen;
List *elem;
if (!unexpanded_variadic_parm)
return;
if (SwigType_isvariadic(t)) {
/* Based on expand_variadic_parms() but input is single SwigType (t) instead of ParmList */
String *unexpanded_name = Getattr(unexpanded_variadic_parm, "name");
ParmList *expanded = CopyParmList(expanded_variadic_parms);
Parm *ep = expanded;
while (ep) {
SwigType *newtype = Copy(t);
SwigType_del_variadic(newtype);
Replaceid(newtype, unexpanded_name, Getattr(ep, "type"));
Setattr(ep, "type", newtype);
ep = nextSibling(ep);
}
Clear(t);
SwigType *fparms = SwigType_function_parms_only(expanded);
Append(t, fparms);
Delete(expanded);
return;
}
nt = NewStringEmpty();
elem = SwigType_split(t);
ilen = Len(elem);
for (i = 0; i < ilen; i++) {
String *e = Getitem(elem, i);
if (SwigType_isfunction(e)) {
int j, jlen;
List *fparms = SwigType_parmlist(e);
Clear(e);
Append(e, "f(");
jlen = Len(fparms);
for (j = 0; j < jlen; j++) {
SwigType *type = Getitem(fparms, j);
SwigType_variadic_replace(type, unexpanded_variadic_parm, expanded_variadic_parms);
if (Len(type) > 0) {
if (j != 0)
Putc(',', e);
Append(e, type);
} else {
assert(j == jlen - 1); /* A variadic parm was replaced with zero parms, variadic parms are only changed at the end of the list */
}
}
Append(e, ").");
Delete(fparms);
}
Append(nt, e);
}
Clear(t);
Append(t, nt);
Delete(nt);
Delete(elem);
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* SwigType_remove_global_scope_prefix() * SwigType_remove_global_scope_prefix()
* *

View file

@ -137,6 +137,7 @@ extern "C" {
extern SwigType *SwigType_add_template(SwigType *t, ParmList *parms); extern SwigType *SwigType_add_template(SwigType *t, ParmList *parms);
extern SwigType *SwigType_pop_function(SwigType *t); extern SwigType *SwigType_pop_function(SwigType *t);
extern SwigType *SwigType_pop_function_qualifiers(SwigType *t); extern SwigType *SwigType_pop_function_qualifiers(SwigType *t);
extern SwigType *SwigType_function_parms_only(ParmList *parms);
extern ParmList *SwigType_function_parms(const SwigType *t, Node *file_line_node); extern ParmList *SwigType_function_parms(const SwigType *t, Node *file_line_node);
extern List *SwigType_split(const SwigType *t); extern List *SwigType_split(const SwigType *t);
extern String *SwigType_pop(SwigType *t); extern String *SwigType_pop(SwigType *t);
@ -187,6 +188,7 @@ extern "C" {
extern SwigType *SwigType_default_create(const SwigType *ty); extern SwigType *SwigType_default_create(const SwigType *ty);
extern SwigType *SwigType_default_deduce(const SwigType *t); extern SwigType *SwigType_default_deduce(const SwigType *t);
extern void SwigType_typename_replace(SwigType *t, String *pat, String *rep); extern void SwigType_typename_replace(SwigType *t, String *pat, String *rep);
extern void SwigType_variadic_replace(SwigType *t, Parm *unexpanded_variadic_parm, ParmList *expanded_variadic_parms);
extern SwigType *SwigType_remove_global_scope_prefix(const SwigType *t); extern SwigType *SwigType_remove_global_scope_prefix(const SwigType *t);
extern SwigType *SwigType_alttype(const SwigType *t, int ltmap); extern SwigType *SwigType_alttype(const SwigType *t, int ltmap);

View file

@ -287,6 +287,7 @@ String *SwigType_parm(const SwigType *t) {
* SwigType_split() * SwigType_split()
* *
* Splits a type into its component parts and returns a list of string. * Splits a type into its component parts and returns a list of string.
* The component parts of SwigType are split by '.'.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
List *SwigType_split(const SwigType *t) { List *SwigType_split(const SwigType *t) {
@ -312,7 +313,7 @@ List *SwigType_split(const SwigType *t) {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* SwigType_parmlist() * SwigType_parmlist()
* *
* Splits a comma separated list of parameters into its component parts * Splits a comma separated list of SwigType * parameters into its component parts
* The input is expected to contain the parameter list within () brackets * The input is expected to contain the parameter list within () brackets
* Returns 0 if no argument list in the input, ie there are no round brackets () * Returns 0 if no argument list in the input, ie there are no round brackets ()
* Returns an empty List if there are no parameters in the () brackets * Returns an empty List if there are no parameters in the () brackets
@ -320,12 +321,12 @@ List *SwigType_split(const SwigType *t) {
* *
* Foo(std::string,p.f().Bar<(int,double)>) * Foo(std::string,p.f().Bar<(int,double)>)
* *
* returns 2 elements in the list: * returns 2 SwigType * elements in the list:
* std::string * std::string
* p.f().Bar<(int,double)> * p.f().Bar<(int,double)>
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
List *SwigType_parmlist(const String *p) { List *SwigType_parmlist(const SwigType *p) {
String *item = 0; String *item = 0;
List *list; List *list;
char *c; char *c;
@ -864,26 +865,42 @@ SwigType *SwigType_array_type(const SwigType *ty) {
* Functions * Functions
* *
* SwigType_add_function() * SwigType_add_function()
* SwigType_function_parms_only()
* SwigType_isfunction() * SwigType_isfunction()
* SwigType_pop_function() * SwigType_pop_function()
* *
* Add, remove, and test for function types. * Add, remove, and test for function types.
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
/* Returns the function type, t, constructed from the parameters, parms */ /* -----------------------------------------------------------------------------
SwigType *SwigType_add_function(SwigType *t, ParmList *parms) { * SwigType_function_parms_only()
String *pstr; *
Parm *p; * Creates a comma separated list of SwigType strings from parms
* ----------------------------------------------------------------------------- */
Insert(t, 0, ")."); SwigType *SwigType_function_parms_only(ParmList *parms) {
pstr = NewString("f("); Parm *p;
SwigType *t = NewString("");
for (p = parms; p; p = nextSibling(p)) { for (p = parms; p; p = nextSibling(p)) {
if (p != parms) if (p != parms)
Putc(',', pstr); Putc(',', t);
Append(pstr, Getattr(p, "type")); Append(t, Getattr(p, "type"));
} }
Insert(t, 0, pstr); return t;
Delete(pstr); }
/* -----------------------------------------------------------------------------
* SwigType_add_function()
*
* Returns the function type, t, constructed from the parameters, parms
* ----------------------------------------------------------------------------- */
SwigType *SwigType_add_function(SwigType *t, ParmList *parms) {
SwigType *fparms = SwigType_function_parms_only(parms);
Insert(fparms, 0, "f(");
Append(fparms, ").");
Insert(t, 0, fparms);
Delete(fparms);
return t; return t;
} }