From 9e19fe7868d6d901c45329873ba02f09a7942542 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sat, 19 Aug 2017 01:02:34 +0100 Subject: [PATCH 01/15] C++11 ref-qualifier support added Fixes #1059 Methods with rvalue ref-qualifiers are ignored by default as it is not possible to have an rvalue temporary from the target language (which is needed to call the rvalue ref-qualified method). A warning 405 is shown mentioning the ignored rvalue ref-qualifier method which can be seen with the -Wextra option. cpp_refqualifier.i:15: Warning 405: Method with rvalue ref-qualifier ignored h() const &&. Usually rvalue and lvalue ref-qualifier overloaded methods are written - the lvalue method will then be wrapped. --- Examples/test-suite/common.mk | 1 + Examples/test-suite/cpp11_ref_qualifiers.i | 16 ++++ Examples/test-suite/errors/cpp_refqualifier.i | 18 +++++ .../test-suite/errors/cpp_refqualifier.stderr | 6 ++ .../java/cpp11_ref_qualifiers_runme.java | 22 ++++++ .../python/cpp11_ref_qualifiers_runme.py | 6 ++ Source/CParse/parser.y | 74 ++++++++++++++++--- Source/Include/swigwarn.h | 1 + Source/Modules/main.cxx | 15 ++-- Source/Swig/naming.c | 4 + 10 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 Examples/test-suite/cpp11_ref_qualifiers.i create mode 100644 Examples/test-suite/errors/cpp_refqualifier.i create mode 100644 Examples/test-suite/errors/cpp_refqualifier.stderr create mode 100644 Examples/test-suite/java/cpp11_ref_qualifiers_runme.java create mode 100644 Examples/test-suite/python/cpp11_ref_qualifiers_runme.py diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index e3448dcbc..b47b6e33b 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -561,6 +561,7 @@ CPP11_TEST_CASES += \ cpp11_noexcept \ cpp11_null_pointer_constant \ cpp11_raw_string_literals \ + cpp11_ref_qualifiers \ cpp11_result_of \ cpp11_rvalue_reference \ cpp11_rvalue_reference2 \ diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i new file mode 100644 index 000000000..fa1d68d0e --- /dev/null +++ b/Examples/test-suite/cpp11_ref_qualifiers.i @@ -0,0 +1,16 @@ +%module cpp11_ref_qualifiers + +%inline %{ +class Host { +public: + void h1() & {} + void h2() const & {} + void h3() && {} + void h4() const && {} + + void h() & {} + void h() const & {} + void h() && {} + void h() const && {} +}; +%} diff --git a/Examples/test-suite/errors/cpp_refqualifier.i b/Examples/test-suite/errors/cpp_refqualifier.i new file mode 100644 index 000000000..1cbcd936d --- /dev/null +++ b/Examples/test-suite/errors/cpp_refqualifier.i @@ -0,0 +1,18 @@ +%module cpp_refqualifier + +%ignore Host::h_ignored; + +class Host { +public: + void h1() &; + void h2() const &; + void h3() &&; + void h4() const &&; + + void h() &; + void h() const &; + void h() &&; + void h() const &&; + + void h_ignored() &&; +}; diff --git a/Examples/test-suite/errors/cpp_refqualifier.stderr b/Examples/test-suite/errors/cpp_refqualifier.stderr new file mode 100644 index 000000000..866d9b530 --- /dev/null +++ b/Examples/test-suite/errors/cpp_refqualifier.stderr @@ -0,0 +1,6 @@ +cpp_refqualifier.i:9: Warning 405: Method with rvalue ref-qualifier ignored h3() &&. +cpp_refqualifier.i:10: Warning 405: Method with rvalue ref-qualifier ignored h4() const &&. +cpp_refqualifier.i:14: Warning 405: Method with rvalue ref-qualifier ignored h() &&. +cpp_refqualifier.i:15: Warning 405: Method with rvalue ref-qualifier ignored h() const &&. +cpp_refqualifier.i:13: Warning 512: Overloaded method Host::h() const & ignored, +cpp_refqualifier.i:12: Warning 512: using non-const method Host::h() & instead. diff --git a/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java new file mode 100644 index 000000000..49afe8039 --- /dev/null +++ b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java @@ -0,0 +1,22 @@ + +import cpp11_ref_qualifiers.*; + +public class cpp11_ref_qualifiers_runme { + + static { + try { + System.loadLibrary("cpp11_ref_qualifiers"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + Host h = new Host(); + h.h1(); + h.h2(); + h.h(); + } +} + diff --git a/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py new file mode 100644 index 000000000..24ce1d2bf --- /dev/null +++ b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py @@ -0,0 +1,6 @@ +import cpp11_ref_qualifiers + +h = cpp11_ref_qualifiers.Host() +h.h1() +h.h2() +h.h() diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index a4167b12d..9a101b1d2 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -485,6 +485,16 @@ static void add_symbols(Node *n) { SetFlag(n,"deleted"); SetFlag(n,"feature:ignore"); } + { + String *refqualifier = Getattr(n, "refqualifier"); + if (Equal(refqualifier, "&&") && strncmp(Char(symname), "$ignore", 7) != 0) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED, Getfile(n), Getline(n), + "Method with rvalue ref-qualifier ignored %s.\n", Swig_name_decl(n)); + SWIG_WARN_NODE_END(n); + SetFlag(n, "feature:ignore"); + } + } } if (only_csymbol || GetFlag(n,"feature:ignore") || strncmp(Char(symname),"$ignore",7) == 0) { /* Only add to C symbol table and continue */ @@ -1451,6 +1461,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) String *rawval; int type; String *qualifier; + String *refqualifier; String *bitfield; Parm *throws; String *throwf; @@ -1560,7 +1571,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) /* Misc */ %type identifier; -%type initializer cpp_const exception_specification; +%type initializer cpp_const exception_specification cv_ref_qualifier; %type storage_class extern_string; %type parms ptail rawparms varargs_parms ; %type templateparameters templateparameterstail; @@ -1576,7 +1587,8 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) %type expr exprnum exprcompound valexpr; %type ename ; %type less_valparms_greater; -%type type_qualifier ; +%type type_qualifier; +%type ref_qualifier; %type type_qualifier_raw; %type idstring idstringopt; %type pragma_lang; @@ -3063,6 +3075,7 @@ c_decl : storage_class type declarator initializer c_decl_tail { $$ = new_node("cdecl"); if ($4.qualifier) decl = add_qualifier_to_declarator($3.type, $4.qualifier); + Setattr($$,"refqualifier",$4.refqualifier); Setattr($$,"type",$2); Setattr($$,"storage",$1); Setattr($$,"name",$3.id); @@ -3136,6 +3149,7 @@ c_decl : storage_class type declarator initializer c_decl_tail { | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype initializer c_decl_tail { $$ = new_node("cdecl"); if ($4.qualifier) SwigType_push($3.type, $4.qualifier); + Setattr($$,"refqualifier",$4.refqualifier); Setattr($$,"type",$6); Setattr($$,"storage",$1); Setattr($$,"name",$3.id); @@ -3198,6 +3212,7 @@ c_decl_tail : SEMI { | COMMA declarator initializer c_decl_tail { $$ = new_node("cdecl"); if ($3.qualifier) SwigType_push($2.type,$3.qualifier); + Setattr($$,"refqualifier",$3.refqualifier); Setattr($$,"name",$2.id); Setattr($$,"decl",$2.type); Setattr($$,"parms",$2.parms); @@ -3236,13 +3251,15 @@ c_decl_tail : SEMI { initializer : def_args { $$ = $1; $$.qualifier = 0; + $$.refqualifier = 0; $$.throws = 0; $$.throwf = 0; $$.nexcept = 0; } - | type_qualifier def_args { + | cv_ref_qualifier def_args { $$ = $2; - $$.qualifier = $1; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; $$.throws = 0; $$.throwf = 0; $$.nexcept = 0; @@ -3250,13 +3267,15 @@ initializer : def_args { | exception_specification def_args { $$ = $2; $$.qualifier = 0; + $$.refqualifier = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; $$.nexcept = $1.nexcept; } - | type_qualifier exception_specification def_args { + | cv_ref_qualifier exception_specification def_args { $$ = $3; - $$.qualifier = $1; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; $$.throws = $2.throws; $$.throwf = $2.throwf; $$.nexcept = $2.nexcept; @@ -4809,6 +4828,7 @@ cpp_vend : cpp_const SEMI { Clear(scanner_ccode); $$.val = 0; $$.qualifier = $1.qualifier; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; @@ -4818,6 +4838,7 @@ cpp_vend : cpp_const SEMI { Clear(scanner_ccode); $$.val = $3.val; $$.qualifier = $1.qualifier; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; @@ -4827,6 +4848,7 @@ cpp_vend : cpp_const SEMI { skip_balanced('{','}'); $$.val = 0; $$.qualifier = $1.qualifier; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = $1.throws; $$.throwf = $1.throwf; @@ -5828,6 +5850,29 @@ pointer : STAR type_qualifier pointer { } ; +/* cv-qualifier plus C++11 ref-qualifier for non-static member functions */ +cv_ref_qualifier : type_qualifier { + $$.qualifier = $1; + $$.refqualifier = 0; + } + | type_qualifier ref_qualifier { + $$.qualifier = $1; + $$.refqualifier = $2; + } + | ref_qualifier { + $$.qualifier = 0; + $$.refqualifier = $1; + } + ; + +ref_qualifier : AND { + $$ = NewString("&"); + } + | LAND { + $$ = NewString("&&"); + } + ; + type_qualifier : type_qualifier_raw { $$ = NewStringEmpty(); if ($1) SwigType_add_qualifier($$,$1); @@ -6049,6 +6094,7 @@ definetype : { /* scanner_check_typedef(); */ } expr { $$.rawval = NewStringf("%s", $$.val); } $$.qualifier = 0; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; @@ -6074,6 +6120,7 @@ deleted_definition : DELETE_KW { $$.rawval = 0; $$.type = T_STRING; $$.qualifier = 0; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; @@ -6087,6 +6134,7 @@ explicit_default : DEFAULT { $$.rawval = 0; $$.type = T_STRING; $$.qualifier = 0; + $$.refqualifier = 0; $$.bitfield = 0; $$.throws = 0; $$.throwf = 0; @@ -6616,25 +6664,29 @@ exception_specification : THROW LPAREN parms RPAREN { } ; -cpp_const : type_qualifier { +cpp_const : cv_ref_qualifier { $$.throws = 0; $$.throwf = 0; $$.nexcept = 0; - $$.qualifier = $1; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; } | exception_specification { $$ = $1; $$.qualifier = 0; + $$.refqualifier = 0; } - | type_qualifier exception_specification { + | cv_ref_qualifier exception_specification { $$ = $2; - $$.qualifier = $1; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; } | empty { $$.throws = 0; $$.throwf = 0; $$.nexcept = 0; - $$.qualifier = 0; + $$.qualifier = 0; + $$.refqualifier = 0; } ; diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h index 0b4c7eeb5..dd32aef3a 100644 --- a/Source/Include/swigwarn.h +++ b/Source/Include/swigwarn.h @@ -153,6 +153,7 @@ #define WARN_TYPE_INCOMPLETE 402 #define WARN_TYPE_ABSTRACT 403 #define WARN_TYPE_REDEFINED 404 +#define WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED 405 #define WARN_TYPEMAP_SOURCETARGET 450 #define WARN_TYPEMAP_CHARLEAK 451 diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx index 12b83b2e4..9822b6af7 100644 --- a/Source/Modules/main.cxx +++ b/Source/Modules/main.cxx @@ -38,14 +38,15 @@ int NoExcept = 0; int SwigRuntime = 0; // 0 = no option, 1 = -runtime, 2 = -noruntime /* Suppress warning messages for private inheritance, preprocessor evaluation etc... - WARN_PP_EVALUATION 202 - WARN_PARSE_PRIVATE_INHERIT 309 - WARN_TYPE_ABSTRACT 403 - WARN_LANG_OVERLOAD_CONST 512 - WARN_PARSE_BUILTIN_NAME 321 - WARN_PARSE_REDUNDANT 322 + WARN_PP_EVALUATION 202 + WARN_PARSE_PRIVATE_INHERIT 309 + WARN_PARSE_BUILTIN_NAME 321 + WARN_PARSE_REDUNDANT 322 + WARN_TYPE_ABSTRACT 403 + WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED 405 + WARN_LANG_OVERLOAD_CONST 512 */ -#define EXTRA_WARNINGS "202,309,403,512,321,322" +#define EXTRA_WARNINGS "202,309,403,405,512,321,322" extern "C" { extern String *ModuleName; diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c index ce1dbe806..69b9e2190 100644 --- a/Source/Swig/naming.c +++ b/Source/Swig/naming.c @@ -1681,6 +1681,7 @@ String *Swig_name_str(Node *n) { * "MyNameSpace::MyTemplate::~MyTemplate()" * "MyNameSpace::ABC::ABC(int,double)" * "MyNameSpace::ABC::constmethod(int) const" + * "MyNameSpace::ABC::refqualifiermethod(int) const &" * "MyNameSpace::ABC::variablename" * * ----------------------------------------------------------------------------- */ @@ -1688,6 +1689,7 @@ String *Swig_name_str(Node *n) { String *Swig_name_decl(Node *n) { String *qname; String *decl; + String *refqualifier = Getattr(n, "refqualifier"); qname = Swig_name_str(n); @@ -1695,6 +1697,8 @@ String *Swig_name_decl(Node *n) { decl = NewStringf("%s", qname); else decl = NewStringf("%s(%s)%s", qname, ParmList_errorstr(Getattr(n, "parms")), SwigType_isconst(Getattr(n, "decl")) ? " const" : ""); + if (refqualifier) + Printv(decl, " ", refqualifier, NIL); Delete(qname); From 685ee6cdc46bd4833851e0a55f535e9cfd18a978 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sat, 19 Aug 2017 09:38:19 +0100 Subject: [PATCH 02/15] Use normal SWIG encodings for ref-qualifiers --- Source/CParse/parser.y | 8 +++++--- Source/Swig/naming.c | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 9a101b1d2..80ec8611e 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -487,7 +487,7 @@ static void add_symbols(Node *n) { } { String *refqualifier = Getattr(n, "refqualifier"); - if (Equal(refqualifier, "&&") && strncmp(Char(symname), "$ignore", 7) != 0) { + if (SwigType_isrvalue_reference(refqualifier) && strncmp(Char(symname), "$ignore", 7) != 0) { SWIG_WARN_NODE_BEGIN(n); Swig_warning(WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED, Getfile(n), Getline(n), "Method with rvalue ref-qualifier ignored %s.\n", Swig_name_decl(n)); @@ -5866,10 +5866,12 @@ cv_ref_qualifier : type_qualifier { ; ref_qualifier : AND { - $$ = NewString("&"); + $$ = NewStringEmpty(); + SwigType_add_reference($$); } | LAND { - $$ = NewString("&&"); + $$ = NewStringEmpty(); + SwigType_add_rvalue_reference($$); } ; diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c index 69b9e2190..4fa32538f 100644 --- a/Source/Swig/naming.c +++ b/Source/Swig/naming.c @@ -1697,8 +1697,11 @@ String *Swig_name_decl(Node *n) { decl = NewStringf("%s", qname); else decl = NewStringf("%s(%s)%s", qname, ParmList_errorstr(Getattr(n, "parms")), SwigType_isconst(Getattr(n, "decl")) ? " const" : ""); - if (refqualifier) - Printv(decl, " ", refqualifier, NIL); + if (refqualifier) { + String *rq = SwigType_str(refqualifier, 0); + Printv(decl, " ", rq, NIL); + Delete(rq); + } Delete(qname); From eeab1529016f34e6f2f8e6e95f8cb465d73d4d6a Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sun, 20 Aug 2017 23:09:04 +0100 Subject: [PATCH 03/15] Fix support for member const function pointer variables Was not generating code that compiled when the variable was not a simple member pointer, for example, a const reference member pointer: short (Funcs::* const& cc7)(bool) const = cc1; --- Examples/test-suite/member_funcptr_galore.i | 22 +++++++++++- Source/CParse/parser.y | 39 +++++++++++++++------ Source/Swig/stype.c | 6 +++- Source/Swig/typeobj.c | 2 +- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Examples/test-suite/member_funcptr_galore.i b/Examples/test-suite/member_funcptr_galore.i index 27d7a386a..01857ff1a 100644 --- a/Examples/test-suite/member_funcptr_galore.i +++ b/Examples/test-suite/member_funcptr_galore.i @@ -6,6 +6,12 @@ %warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) pp3; %warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) pp5; +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) ccextra2; +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) ccextra3; +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc2; +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc3; +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc5; + %{ #if defined(__SUNPRO_CC) #pragma error_messages (off, badargtype2w) /* Formal argument ... is being passed extern "C" ... */ @@ -191,7 +197,7 @@ int MemberFuncPtrs::qqq5(short (Funcs::* & qq5)(bool)) const { return 0; } int MemberFuncPtrs::qqq6(short (Funcs::* const qq6)(bool)) const { return 0; } int MemberFuncPtrs::qqq7(short (Funcs::* const& qq7)(bool)) const { return 0; } -// member function pointer variables +// member non-const function pointer variables short (Funcs::* pp1)(bool) = &Funcs::FF; short (Funcs::* const * extra2)(bool) = &pp1; @@ -204,4 +210,18 @@ short (Funcs::* *const& pp4)(bool) = extra4; short (Funcs::* & pp5)(bool) = pp1; short (Funcs::* const pp6)(bool) = &Funcs::FF; short (Funcs::* const& pp7)(bool) = pp1; + +// member const function pointer variables +short (Funcs::* cc1)(bool) const = &Funcs::CC; + +short (Funcs::* const * ccextra2)(bool) const = &cc1; +short (Funcs::* * ccextra3)(bool) const = &cc1; +short (Funcs::* *const ccextra4)(bool) const = &cc1; + +short (Funcs::* const *& cc2)(bool) const = ccextra2; +short (Funcs::* *& cc3)(bool) const = ccextra3; +short (Funcs::* *const& cc4)(bool) const = ccextra4; +short (Funcs::* & cc5)(bool) const = cc1; +short (Funcs::* const cc6)(bool) const = &Funcs::CC; +short (Funcs::* const& cc7)(bool) const = cc1; %} diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 80ec8611e..bc12997be 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -1432,22 +1432,39 @@ static void mark_nodes_as_extend(Node *n) { static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) { int is_pointer_to_member_function = 0; String *decl = Copy(type); + String *poppedtype = NewString(""); assert(qualifier); - if (SwigType_ismemberpointer(decl)) { - String *memberptr = SwigType_pop(decl); - if (SwigType_isfunction(decl)) { - assert(!SwigType_isqualifier(decl)); - SwigType_push(decl, qualifier); - SwigType_push(decl, memberptr); - is_pointer_to_member_function = 1; + + while (decl) { + if (SwigType_ismemberpointer(decl)) { + String *memberptr = SwigType_pop(decl); + if (SwigType_isfunction(decl)) { + is_pointer_to_member_function = 1; + SwigType_push(decl, qualifier); + SwigType_push(decl, memberptr); + Insert(decl, 0, poppedtype); + Delete(memberptr); + break; + } else { + Append(poppedtype, memberptr); + } + Delete(memberptr); } else { - Delete(decl); - decl = Copy(type); + String *popped = SwigType_pop(decl); + if (!popped) + break; + Append(poppedtype, popped); + Delete(popped); } - Delete(memberptr); } - if (!is_pointer_to_member_function) + + if (!is_pointer_to_member_function) { + Delete(decl); + decl = Copy(type); SwigType_push(decl, qualifier); + } + + Delete(poppedtype); return decl; } diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c index 829005cd9..5cfa3e890 100644 --- a/Source/Swig/stype.c +++ b/Source/Swig/stype.c @@ -670,6 +670,7 @@ SwigType *SwigType_ltype(const SwigType *s) { int nelements, i; int firstarray = 1; int notypeconv = 0; + int memberpointer = 0; result = NewStringEmpty(); tc = Copy(s); @@ -707,13 +708,16 @@ SwigType *SwigType_ltype(const SwigType *s) { notypeconv = 1; } if (SwigType_isqualifier(element)) { - /* Do nothing. Ignore */ + if (memberpointer) + Append(result, element); + /* otherwise ignore */ } else if (SwigType_ispointer(element)) { Append(result, element); firstarray = 0; } else if (SwigType_ismemberpointer(element)) { Append(result, element); firstarray = 0; + memberpointer = 1; } else if (SwigType_isreference(element)) { if (notypeconv) { Append(result, element); diff --git a/Source/Swig/typeobj.c b/Source/Swig/typeobj.c index b2832b6a9..5240927ef 100644 --- a/Source/Swig/typeobj.c +++ b/Source/Swig/typeobj.c @@ -48,7 +48,7 @@ * 'a(n).' = Array of size n [n] * 'f(..,..).' = Function with arguments (args) * 'q(str).' = Qualifier (such as const or volatile) (const, volatile) - * 'm(qual).' = Pointer to member (qual::*) + * 'm(cls).' = Pointer to member (cls::*) * * The complete type representation for varargs is: * 'v(...)' From 1cf599bccb100f3bcda42f5f507ea32f99cd5f89 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Wed, 23 Aug 2017 09:07:12 +0100 Subject: [PATCH 04/15] Improve ref-qualifier implementation Internally, handle function ref-qualifiers in the function decl type string. Needed for a whole host of things to work like %feature and %rename. Add %feature %rename and %ignore testing for ref-qualifiers. --- Examples/test-suite/cpp11_ref_qualifiers.i | 82 ++++++++++++++++--- Examples/test-suite/errors/cpp_refqualifier.i | 4 + .../test-suite/errors/cpp_refqualifier.stderr | 12 +-- .../java/cpp11_ref_qualifiers_runme.java | 25 ++++++ .../python/cpp11_ref_qualifiers_runme.py | 31 +++++++ Source/CParse/parser.y | 20 +++-- Source/Modules/overload.cxx | 18 +++- Source/Swig/naming.c | 23 ++++-- Source/Swig/stype.c | 20 +++-- Source/Swig/swig.h | 1 + Source/Swig/typeobj.c | 81 ++++++++++++++++-- 11 files changed, 265 insertions(+), 52 deletions(-) diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i index fa1d68d0e..2115843a3 100644 --- a/Examples/test-suite/cpp11_ref_qualifiers.i +++ b/Examples/test-suite/cpp11_ref_qualifiers.i @@ -1,16 +1,76 @@ %module cpp11_ref_qualifiers -%inline %{ -class Host { -public: - void h1() & {} - void h2() const & {} - void h3() && {} - void h4() const && {} +%include - void h() & {} - void h() const & {} - void h() && {} - void h() const && {} +%ignore Host::h() const &; + +// Basic testing +%inline %{ +using std::string; +class Host { + string s; +public: + string h1() & { return string(); } + string h2() const & { return string(); } + string h3() && { return std::move(string()); } + string h4() const && { return std::move(string()); } + string h5() const { return string(); } + string h6() volatile const & { return string(); } + string h7() const volatile & { return string(); } + string h8() volatile const && { return std::move(string()); } + string h9() const volatile && { return std::move(string()); } + + string h() & { return string(); } + string h() const & { return string(); } + string h() && { return std::move(string()); } + string h() const && { return std::move(string()); } +}; +%} + +// %feature testing +%feature("except") F1() & %{ result = "F1"; %} +%feature("except") F2 %{ result = "F2"; %} +%feature("except") F3 %{ result = "F3"; %} +%feature("except") F3() %{ _should_not_be_used_ %} + +%feature("except") C1(int i) const & %{ result = "C1"; %} +%feature("except") C2 %{ result = "C2"; %} +%feature("except") C3 %{ result = "C3"; %} +%feature("except") C3(int i) %{ _should_not_be_used_ %} + +%inline %{ +struct Features { + string F1() & { return string(); } + string F2() & { return string(); } + string F3() & { return string(); } + + string C1(int i) const & { return string(); } + string C2(int i) const & { return string(); } + string C3(int i) const & { return string(); } +}; +%} + +// %rename testing +%rename(RR1) R1; +%rename(RR2) R2() &; +%rename(RR3) R3; +%rename(RR3Bad) R3(); + +%rename(SS1) S1; +%rename(SS2) S2(int i) const &; +%rename(SS3) S3; +%rename(SS3Bad) S3(int i); +%rename(SS3BadConst) S3(int i) const; +%rename(SS3BadLValue) S3(int i) &; + +%inline %{ +struct Renames { + string R1() & { return string(); } + string R2() & { return string(); } + string R3() & { return string(); } + + string S1(int i) const & { return string(); } + string S2(int i) const & { return string(); } + string S3(int i) const & { return string(); } }; %} diff --git a/Examples/test-suite/errors/cpp_refqualifier.i b/Examples/test-suite/errors/cpp_refqualifier.i index 1cbcd936d..438aacd93 100644 --- a/Examples/test-suite/errors/cpp_refqualifier.i +++ b/Examples/test-suite/errors/cpp_refqualifier.i @@ -1,6 +1,8 @@ %module cpp_refqualifier %ignore Host::h_ignored; +%ignore Host::i_ignored() &&; +%ignore Host::j_ignored() const &&; class Host { public: @@ -15,4 +17,6 @@ public: void h() const &&; void h_ignored() &&; + void i_ignored() &&; + void j_ignored() const &&; }; diff --git a/Examples/test-suite/errors/cpp_refqualifier.stderr b/Examples/test-suite/errors/cpp_refqualifier.stderr index 866d9b530..ea2cd220a 100644 --- a/Examples/test-suite/errors/cpp_refqualifier.stderr +++ b/Examples/test-suite/errors/cpp_refqualifier.stderr @@ -1,6 +1,6 @@ -cpp_refqualifier.i:9: Warning 405: Method with rvalue ref-qualifier ignored h3() &&. -cpp_refqualifier.i:10: Warning 405: Method with rvalue ref-qualifier ignored h4() const &&. -cpp_refqualifier.i:14: Warning 405: Method with rvalue ref-qualifier ignored h() &&. -cpp_refqualifier.i:15: Warning 405: Method with rvalue ref-qualifier ignored h() const &&. -cpp_refqualifier.i:13: Warning 512: Overloaded method Host::h() const & ignored, -cpp_refqualifier.i:12: Warning 512: using non-const method Host::h() & instead. +cpp_refqualifier.i:11: Warning 405: Method with rvalue ref-qualifier h3() && ignored. +cpp_refqualifier.i:12: Warning 405: Method with rvalue ref-qualifier h4() const && ignored. +cpp_refqualifier.i:16: Warning 405: Method with rvalue ref-qualifier h() && ignored. +cpp_refqualifier.i:17: Warning 405: Method with rvalue ref-qualifier h() const && ignored. +cpp_refqualifier.i:15: Warning 512: Overloaded method Host::h() const & ignored, +cpp_refqualifier.i:14: Warning 512: using non-const method Host::h() & instead. diff --git a/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java index 49afe8039..bbe6be8e3 100644 --- a/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java +++ b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java @@ -14,9 +14,34 @@ public class cpp11_ref_qualifiers_runme { public static void main(String argv[]) { Host h = new Host(); + + // Basic testing h.h1(); h.h2(); + h.h6(); + h.h7(); + h.h(); + + // %feature testing + Features f = new Features(); + if (!f.F1().equals("F1")) throw new RuntimeException("Fail"); + if (!f.F2().equals("F2")) throw new RuntimeException("Fail"); + if (!f.F3().equals("F3")) throw new RuntimeException("Fail"); + + if (!f.C1(0).equals("C1")) throw new RuntimeException("Fail"); + if (!f.C2(0).equals("C2")) throw new RuntimeException("Fail"); + if (!f.C3(0).equals("C3")) throw new RuntimeException("Fail"); + + // %rename testing + Renames r = new Renames(); + r.RR1(); + r.RR2(); + r.RR3(); + + r.SS1(0); + r.SS2(0); + r.SS3(0); } } diff --git a/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py index 24ce1d2bf..47c474218 100644 --- a/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py +++ b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py @@ -1,6 +1,37 @@ import cpp11_ref_qualifiers h = cpp11_ref_qualifiers.Host() + +# Basic testing h.h1() h.h2() +h.h6() +h.h7() + h.h() + +# %feature testing +f = cpp11_ref_qualifiers.Features() +if f.F1() != "F1": + raise RuntimeException("Fail") +if f.F2() != "F2": + raise RuntimeException("Fail") +if f.F3() != "F3": + raise RuntimeException("Fail") + +if f.C1(0) != "C1": + raise RuntimeException("Fail") +if f.C2(0) != "C2": + raise RuntimeException("Fail") +if f.C3(0) != "C3": + raise RuntimeException("Fail") + +# %rename testing +r = cpp11_ref_qualifiers.Renames() +r.RR1() +r.RR2() +r.RR3() + +r.SS1(0) +r.SS2(0) +r.SS3(0) diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index bc12997be..ccb09e3eb 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -487,16 +487,16 @@ static void add_symbols(Node *n) { } { String *refqualifier = Getattr(n, "refqualifier"); - if (SwigType_isrvalue_reference(refqualifier) && strncmp(Char(symname), "$ignore", 7) != 0) { + if (SwigType_isrvalue_reference(refqualifier) && Strcmp(symname, "$ignore") != 0) { SWIG_WARN_NODE_BEGIN(n); Swig_warning(WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED, Getfile(n), Getline(n), - "Method with rvalue ref-qualifier ignored %s.\n", Swig_name_decl(n)); + "Method with rvalue ref-qualifier %s ignored.\n", Swig_name_decl(n)); SWIG_WARN_NODE_END(n); SetFlag(n, "feature:ignore"); } } } - if (only_csymbol || GetFlag(n,"feature:ignore") || strncmp(Char(symname),"$ignore",7) == 0) { + if (only_csymbol || GetFlag(n, "feature:ignore") || Strncmp(symname, "$ignore", 7) == 0) { /* Only add to C symbol table and continue */ Swig_symbol_add(0, n); if (!only_csymbol && !GetFlag(n, "feature:ignore")) { @@ -1421,10 +1421,12 @@ static void mark_nodes_as_extend(Node *n) { } /* ----------------------------------------------------------------------------- - * add_qualifier_to_declarator + * add_qualifier_to_declarator() * + * Normally the qualifier is pushed on to the front of the type. * Adding a qualifier to a pointer to member function is a special case. * For example : typedef double (Cls::*pmf)(void) const; + * The qualifier is : q(const). * The declarator is : m(Cls).f(void). * We need : m(Cls).q(const).f(void). * ----------------------------------------------------------------------------- */ @@ -5870,15 +5872,17 @@ pointer : STAR type_qualifier pointer { /* cv-qualifier plus C++11 ref-qualifier for non-static member functions */ cv_ref_qualifier : type_qualifier { $$.qualifier = $1; - $$.refqualifier = 0; + $$.refqualifier = 0; } | type_qualifier ref_qualifier { $$.qualifier = $1; - $$.refqualifier = $2; + $$.refqualifier = $2; + SwigType_push($$.qualifier, $2); } | ref_qualifier { - $$.qualifier = 0; - $$.refqualifier = $1; + $$.qualifier = NewStringEmpty(); + $$.refqualifier = $1; + SwigType_push($$.qualifier, $1); } ; diff --git a/Source/Modules/overload.cxx b/Source/Modules/overload.cxx index 330294efd..81d1bb000 100644 --- a/Source/Modules/overload.cxx +++ b/Source/Modules/overload.cxx @@ -231,9 +231,21 @@ List *Swig_overload_rank(Node *n, bool script_lang_wrapping) { } if (!differ) { /* See if declarations differ by const only */ - String *d1 = Getattr(nodes[i].n, "decl"); - String *d2 = Getattr(nodes[j].n, "decl"); - if (d1 && d2) { + String *decl1 = Getattr(nodes[i].n, "decl"); + String *decl2 = Getattr(nodes[j].n, "decl"); + if (decl1 && decl2) { + /* Remove ref-qualifiers. Note that rvalue ref-qualifiers are already ignored and + * it is illegal to overload a function with and without ref-qualifiers. So with + * all the combinations of ref-qualifiers and cv-qualifiers, we just detect + * the cv-qualifier (const) overloading. */ + String *d1 = Copy(decl1); + String *d2 = Copy(decl2); + if (SwigType_isreference(d1) || SwigType_isrvalue_reference(d1)) { + Delete(SwigType_pop(d1)); + } + if (SwigType_isreference(d2) || SwigType_isrvalue_reference(d2)) { + Delete(SwigType_pop(d2)); + } String *dq1 = Copy(d1); String *dq2 = Copy(d2); if (SwigType_isconst(d1)) { diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c index 4fa32538f..d12770125 100644 --- a/Source/Swig/naming.c +++ b/Source/Swig/naming.c @@ -1689,18 +1689,23 @@ String *Swig_name_str(Node *n) { String *Swig_name_decl(Node *n) { String *qname; String *decl; - String *refqualifier = Getattr(n, "refqualifier"); qname = Swig_name_str(n); + decl = NewStringf("%s", qname); - if (checkAttribute(n, "kind", "variable")) - decl = NewStringf("%s", qname); - else - decl = NewStringf("%s(%s)%s", qname, ParmList_errorstr(Getattr(n, "parms")), SwigType_isconst(Getattr(n, "decl")) ? " const" : ""); - if (refqualifier) { - String *rq = SwigType_str(refqualifier, 0); - Printv(decl, " ", rq, NIL); - Delete(rq); + if (!checkAttribute(n, "kind", "variable")) { + String *d = Getattr(n, "decl"); + Printv(decl, "(", ParmList_errorstr(Getattr(n, "parms")), ")", NIL); + if (SwigType_isfunction(d)) { + SwigType *decl_temp = Copy(d); + SwigType *qualifiers = SwigType_pop_function_qualifiers(decl_temp); + if (qualifiers) { + String *qualifiers_string = SwigType_str(qualifiers, 0); + Printv(decl, " ", qualifiers_string, NIL); + Delete(qualifiers_string); + } + Delete(decl_temp); + } } Delete(qname); diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c index 5cfa3e890..4b745b335 100644 --- a/Source/Swig/stype.c +++ b/Source/Swig/stype.c @@ -44,7 +44,7 @@ * 'z.' = Rvalue reference (&&) * 'a(n).' = Array of size n [n] * 'f(..,..).' = Function with arguments (args) - * 'q(str).' = Qualifier (such as const or volatile) (const, volatile) + * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) * 'm(cls).' = Pointer to member (cls::*) * * The encoding follows the order that you might describe a type in words. @@ -64,11 +64,19 @@ * * More examples: * - * String Encoding C++ Example - * --------------- ----------- - * p.f(bool).q(const).long const long (*)(bool) - * m(Funcs).q(const).f(bool).long long (Funcs::*)(bool) const - * r.q(const).m(Funcs).f(int).long long (Funcs::*const &)(int) + * String Encoding C++ Example + * --------------- ----------- + * p.f(bool).r.q(const).long const long & (*)(bool) + * m(Funcs).q(const).f(bool).long long (Funcs::*)(bool) const + * r.q(const).m(Funcs).f(int).long long (Funcs::*const &)(int) + * m(Funcs).z.q(const).f(bool).long long (Funcs::*)(bool) const && + * + * Function decl examples: + * + * f(bool). long a(bool); + * r.f(bool). long b(bool) &; + * z.f(bool). long c(bool) &&; + * z.q(const).f(bool). long d(bool) const &&; * * For the most part, this module tries to minimize the use of special * characters (*, [, <, etc...) in its type encoding. One reason for this diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h index 0bcd53a66..7452c374c 100644 --- a/Source/Swig/swig.h +++ b/Source/Swig/swig.h @@ -136,6 +136,7 @@ extern "C" { extern SwigType *SwigType_add_function(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_qualifiers(SwigType *t); extern ParmList *SwigType_function_parms(const SwigType *t, Node *file_line_node); extern List *SwigType_split(const SwigType *t); extern String *SwigType_pop(SwigType *t); diff --git a/Source/Swig/typeobj.c b/Source/Swig/typeobj.c index 5240927ef..7a0626c29 100644 --- a/Source/Swig/typeobj.c +++ b/Source/Swig/typeobj.c @@ -43,11 +43,11 @@ * All type constructors are denoted by a trailing '.': * * 'p.' = Pointer (*) - * 'r.' = Reference (&) - * 'z.' = Rvalue reference (&&) + * 'r.' = Reference or ref-qualifier (&) + * 'z.' = Rvalue reference or ref-qualifier (&&) * 'a(n).' = Array of size n [n] * 'f(..,..).' = Function with arguments (args) - * 'q(str).' = Qualifier (such as const or volatile) (const, volatile) + * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) * 'm(cls).' = Pointer to member (cls::*) * * The complete type representation for varargs is: @@ -183,9 +183,10 @@ SwigType *SwigType_del_element(SwigType *t) { * SwigType_pop() * * Pop one type element off the type. - * Example: t in: q(const).p.Integer - * t out: p.Integer - * result: q(const). + * For example: + * t in: q(const).p.Integer + * t out: p.Integer + * result: q(const). * ----------------------------------------------------------------------------- */ SwigType *SwigType_pop(SwigType *t) { @@ -771,7 +772,6 @@ SwigType *SwigType_array_type(const SwigType *ty) { * Functions * * SwigType_add_function() - * SwigType_del_function() * SwigType_isfunction() * SwigType_pop_function() * @@ -795,14 +795,36 @@ SwigType *SwigType_add_function(SwigType *t, ParmList *parms) { return t; } +/* ----------------------------------------------------------------------------- + * SwigType_pop_function() + * + * Pop and return the function from the input type leaving the function's return + * type, if any. + * For example: + * t in: q(const).f().p. + * t out: p. + * result: q(const).f(). + * ----------------------------------------------------------------------------- */ + SwigType *SwigType_pop_function(SwigType *t) { SwigType *f = 0; SwigType *g = 0; char *c = Char(t); - if (strncmp(c, "q(", 2) == 0) { + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Remove ref-qualifier */ f = SwigType_pop(t); c = Char(t); } + if (strncmp(c, "q(", 2) == 0) { + /* Remove cv-qualifier */ + String *qual = SwigType_pop(t); + if (f) { + SwigType_push(qual, f); + Delete(f); + } + f = qual; + c = Char(t); + } if (strncmp(c, "f(", 2)) { printf("Fatal error. SwigType_pop_function applied to non-function.\n"); abort(); @@ -814,14 +836,55 @@ SwigType *SwigType_pop_function(SwigType *t) { return g; } +/* ----------------------------------------------------------------------------- + * SwigType_pop_function_qualifiers() + * + * Pop and return the function qualifiers from the input type leaving the rest of + * function declaration. Returns NULL if no qualifiers. + * For example: + * t in: r.q(const).f().p. + * t out: f().p. + * result: r.q(const) + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_pop_function_qualifiers(SwigType *t) { + SwigType *qualifiers = 0; + char *c = Char(t); + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Remove ref-qualifier */ + String *qual = SwigType_pop(t); + qualifiers = qual; + c = Char(t); + } + if (strncmp(c, "q(", 2) == 0) { + /* Remove cv-qualifier */ + String *qual = SwigType_pop(t); + if (qualifiers) { + SwigType_push(qual, qualifiers); + Delete(qualifiers); + } + qualifiers = qual; + c = Char(t); + } + assert(strncmp(c, "f(", 2) == 0); + + return qualifiers; +} + int SwigType_isfunction(const SwigType *t) { char *c; if (!t) { return 0; } c = Char(t); + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Might be a function with a ref-qualifier, skip over */ + c += 2; + if (!*c) + return 0; + } if (strncmp(c, "q(", 2) == 0) { - /* Might be a 'const' function. Try to skip over the 'const' */ + /* Might be a function with a cv-qualifier, skip over */ c = strchr(c, '.'); if (c) c++; From 8a40327aa8f75af9d5c68bfee1125be4544f2865 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 25 Aug 2017 19:08:09 +0100 Subject: [PATCH 05/15] Add unignore for rvalue ref-qualifiers Use std::move on this pointer as the default approach to supporting rvalue ref-qualifiers if a user really wants to wrap. std::move requires headers so add swigfragments.swg for all languages to use common fragments. Just header file fragments for now. --- Examples/test-suite/common.mk | 1 + .../cpp11_ref_qualifiers_rvalue_unignore.i | 15 ++++ Examples/test-suite/errors/cpp_refqualifier.i | 8 +- ..._ref_qualifiers_rvalue_unignore_runme.java | 20 +++++ ...11_ref_qualifiers_rvalue_unignore_runme.py | 4 + Lib/swig.swg | 4 +- Lib/swigfragments.swg | 86 +++++++++++++++++++ Lib/typemaps/fragments.swg | 69 --------------- Source/CParse/parser.y | 7 +- Source/Swig/cwrap.c | 9 ++ 10 files changed, 149 insertions(+), 74 deletions(-) create mode 100644 Examples/test-suite/cpp11_ref_qualifiers_rvalue_unignore.i create mode 100644 Examples/test-suite/java/cpp11_ref_qualifiers_rvalue_unignore_runme.java create mode 100644 Examples/test-suite/python/cpp11_ref_qualifiers_rvalue_unignore_runme.py create mode 100644 Lib/swigfragments.swg diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index b47b6e33b..0d0a32c8c 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -562,6 +562,7 @@ CPP11_TEST_CASES += \ cpp11_null_pointer_constant \ cpp11_raw_string_literals \ cpp11_ref_qualifiers \ + cpp11_ref_qualifiers_rvalue_unignore \ cpp11_result_of \ cpp11_rvalue_reference \ cpp11_rvalue_reference2 \ diff --git a/Examples/test-suite/cpp11_ref_qualifiers_rvalue_unignore.i b/Examples/test-suite/cpp11_ref_qualifiers_rvalue_unignore.i new file mode 100644 index 000000000..2f5fadfc6 --- /dev/null +++ b/Examples/test-suite/cpp11_ref_qualifiers_rvalue_unignore.i @@ -0,0 +1,15 @@ +%module cpp11_ref_qualifiers_rvalue_unignore + +// This is a minimal test that does not include any C++ headers to make sure the required +// header is generated from a fragment for the generated std::move call + +// m1 and m2 are ignored by default, unignore them +%feature("ignore", "0") RefQualifier::m1() &&; +%feature("ignore", "0") RefQualifier::m2() const &&; + +%inline %{ +struct RefQualifier { + void m1() && {} + void m2() const && {} +}; +%} diff --git a/Examples/test-suite/errors/cpp_refqualifier.i b/Examples/test-suite/errors/cpp_refqualifier.i index 438aacd93..afd6632fc 100644 --- a/Examples/test-suite/errors/cpp_refqualifier.i +++ b/Examples/test-suite/errors/cpp_refqualifier.i @@ -18,5 +18,11 @@ public: void h_ignored() &&; void i_ignored() &&; - void j_ignored() const &&; + void i_ignored() &&; +}; + +%feature("ignore", "0") Unignore::k_unignored() const &&; + +struct Unignore { + void k_unignored() const &&; }; diff --git a/Examples/test-suite/java/cpp11_ref_qualifiers_rvalue_unignore_runme.java b/Examples/test-suite/java/cpp11_ref_qualifiers_rvalue_unignore_runme.java new file mode 100644 index 000000000..bbbe6f788 --- /dev/null +++ b/Examples/test-suite/java/cpp11_ref_qualifiers_rvalue_unignore_runme.java @@ -0,0 +1,20 @@ + +import cpp11_ref_qualifiers_rvalue_unignore.*; + +public class cpp11_ref_qualifiers_rvalue_unignore_runme { + + static { + try { + System.loadLibrary("cpp11_ref_qualifiers_rvalue_unignore"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + new RefQualifier().m1(); + new RefQualifier().m2(); + } +} + diff --git a/Examples/test-suite/python/cpp11_ref_qualifiers_rvalue_unignore_runme.py b/Examples/test-suite/python/cpp11_ref_qualifiers_rvalue_unignore_runme.py new file mode 100644 index 000000000..6352c79c2 --- /dev/null +++ b/Examples/test-suite/python/cpp11_ref_qualifiers_rvalue_unignore_runme.py @@ -0,0 +1,4 @@ +import cpp11_ref_qualifiers_rvalue_unignore + +cpp11_ref_qualifiers_rvalue_unignore.RefQualifier().m1() +cpp11_ref_qualifiers_rvalue_unignore.RefQualifier().m2() diff --git a/Lib/swig.swg b/Lib/swig.swg index 6f48f0d20..6dc215dcf 100644 --- a/Lib/swig.swg +++ b/Lib/swig.swg @@ -309,11 +309,13 @@ static int NAME(TYPE x) { %define %$classname %$ismember,"match$parentNode$name" %enddef %define %$isnested "match$nested"="1" %enddef + /* ----------------------------------------------------------------------------- - * Include all the warnings labels and macros + * Common includes for warning labels, macros, fragments etc * ----------------------------------------------------------------------------- */ %include +%include /* ----------------------------------------------------------------------------- * Overloading support diff --git a/Lib/swigfragments.swg b/Lib/swigfragments.swg new file mode 100644 index 000000000..63bb6c8f4 --- /dev/null +++ b/Lib/swigfragments.swg @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------- + * swigfragments.swg + * + * Common fragments + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * Fragments for C header files + * ----------------------------------------------------------------------------- */ + +%fragment("", "header") %{ +#include +%} + +/* Default compiler options for gcc allow long_long but not LLONG_MAX. + * Define SWIG_NO_LLONG_MAX if this added limits support is not wanted. */ +%fragment("", "header") %{ +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif +%} + +%fragment("", "header") %{ +#include +%} + +%fragment("", "header") %{ +#include +%} + +%fragment("", "header") %{ +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif +%} + +%fragment("", "header") %{ +#include +#ifdef _MSC_VER +# ifndef strtoull +# define strtoull _strtoui64 +# endif +# ifndef strtoll +# define strtoll _strtoi64 +# endif +#endif +%} + +%fragment("", "header") %{ +#include +#include +#ifndef WCHAR_MIN +# define WCHAR_MIN 0 +#endif +#ifndef WCHAR_MAX +# define WCHAR_MAX 65535 +#endif +%} + +/* ----------------------------------------------------------------------------- + * Fragments for C++ header files + * ----------------------------------------------------------------------------- */ + +%fragment("", "header") %{ +#include +%} + +%fragment("", "header") %{ +#include +%} + +%fragment("", "header") %{ +#include +%} + +%fragment("", "header") %{ +#include +%} diff --git a/Lib/typemaps/fragments.swg b/Lib/typemaps/fragments.swg index 3f33ca98d..aaf948c05 100644 --- a/Lib/typemaps/fragments.swg +++ b/Lib/typemaps/fragments.swg @@ -96,75 +96,6 @@ * common fragments * ------------------------------------------------------------ */ -/* Default compiler options for gcc allow long_long but not LLONG_MAX. - * Define SWIG_NO_LLONG_MAX if this added limits support is not wanted. */ -%fragment("","header") %{ -#include -#if !defined(SWIG_NO_LLONG_MAX) -# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) -# define LLONG_MAX __LONG_LONG_MAX__ -# define LLONG_MIN (-LLONG_MAX - 1LL) -# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -# endif -#endif -%} - -%fragment("","header") %{ -#include -%} - -%fragment("","header") %{ -#include -#include -#ifndef WCHAR_MIN -# define WCHAR_MIN 0 -#endif -#ifndef WCHAR_MAX -# define WCHAR_MAX 65535 -#endif -%} - -%fragment("","header") %{ -#include -%} - -%fragment("","header") %{ -#include -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) -# ifndef snprintf -# define snprintf _snprintf -# endif -#endif -%} - -%fragment("","header") %{ -#include -#ifdef _MSC_VER -# ifndef strtoull -# define strtoull _strtoui64 -# endif -# ifndef strtoll -# define strtoll _strtoi64 -# endif -#endif -%} - -%fragment("", "header") %{ -#include -%} - -%fragment("", "header") %{ -#include -%} - -%fragment("", "header") %{ -#include -%} - -%fragment("", "header") %{ -#include -%} - %fragment("SWIG_isfinite","header",fragment=",") %{ /* Getting isfinite working pre C99 across multiple platforms is non-trivial. Users can provide SWIG_isfinite on older platforms. */ #ifndef SWIG_isfinite diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index ccb09e3eb..3e0fd3282 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -485,9 +485,10 @@ static void add_symbols(Node *n) { SetFlag(n,"deleted"); SetFlag(n,"feature:ignore"); } - { - String *refqualifier = Getattr(n, "refqualifier"); - if (SwigType_isrvalue_reference(refqualifier) && Strcmp(symname, "$ignore") != 0) { + if (SwigType_isrvalue_reference(Getattr(n, "refqualifier"))) { + /* Ignore rvalue ref-qualifiers by default + * Use Getattr instead of GetFlag to handle explicit ignore and explicit not ignore */ + if (!(Getattr(n, "feature:ignore") || Strncmp(symname, "$ignore", 7) == 0)) { SWIG_WARN_NODE_BEGIN(n); Swig_warning(WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED, Getfile(n), Getline(n), "Method with rvalue ref-qualifier %s ignored.\n", Swig_name_decl(n)); diff --git a/Source/Swig/cwrap.c b/Source/Swig/cwrap.c index 4c3135e3a..d6e5e0cdc 100644 --- a/Source/Swig/cwrap.c +++ b/Source/Swig/cwrap.c @@ -1024,6 +1024,15 @@ int Swig_MethodToFunction(Node *n, const_String_or_char_ptr nspace, String *clas } } + if (!self && SwigType_isrvalue_reference(Getattr(n, "refqualifier"))) { + String *memory_header = NewString(""); + Setfile(memory_header, Getfile(n)); + Setline(memory_header, Getline(n)); + Swig_fragment_emit(memory_header); + self = NewString("std::move(*this)."); + Delete(memory_header); + } + call = Swig_cmethod_call(explicitcall_name ? explicitcall_name : name, p, self, explicit_qualifier, director_type); cres = Swig_cresult(Getattr(n, "type"), Swig_cresult_name(), call); From 330ef362f483fc999b6f4045ab85c0897c361352 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 25 Aug 2017 22:52:56 +0100 Subject: [PATCH 06/15] Add docs for C++11 ref-qualifiers --- CHANGES.current | 23 +++++++++ Doc/Manual/CPlusPlus11.html | 100 ++++++++++++++++++++++++++++++++++++ Doc/Manual/Contents.html | 1 + Doc/Manual/SWIGPlus.html | 28 ++++++++-- Doc/Manual/Typemaps.html | 4 +- 5 files changed, 150 insertions(+), 6 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 0629dfbb6..79c7df479 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,29 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.0.0 (in progress) =========================== +2017-08-25: wsfulton + Issue #1059. Add support for C++11 ref-qualifiers on non-static member functions. + Members with lvalue ref-qualifiers such as: + + struct RQ { + void m1(int x) &; + void m2(int x) const &; + }; + + are wrapped like any other member function. Member functions with rvalue ref-qualifiers + are ignored by default, such as: + + struct RQ { + void m3(int x) &&; + void m4(int x) const &&; + }; + + example.i:7: Warning 405: Method with rvalue ref-qualifier m3(int) && ignored. + example.i:8: Warning 405: Method with rvalue ref-qualifier m4(int) const && ignored. + + These can be unignored and exposed to the target language, see further documentation in + CPlusPlus11.html. + 2017-08-16: wsfulton Fix #1063. Add using declarations to templates into typedef table. diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html index e4dff6543..f9281bd56 100644 --- a/Doc/Manual/CPlusPlus11.html +++ b/Doc/Manual/CPlusPlus11.html @@ -42,6 +42,7 @@
  • Exception specifications and noexcept
  • Control and query object alignment
  • Attributes +
  • Methods with ref-qualifiers
  • Standard library changes
      @@ -971,6 +972,104 @@ int [[attr1]] i [[attr2, attr3]]; [[noreturn, nothrow]] void f [[noreturn]] (); + +

      7.2.29 Methods with ref-qualifiers

      + + +

      +C++11 non-static member functions can be declared with ref-qualifiers. +Member functions declared with a & lvalue ref-qualifiers are wrapped like any other function without ref-qualifiers. +Member functions declared with a && rvalue ref-qualifiers are ignored by default +as they are unlikely to be required from non-C++ languages where the concept of rvalue-ness +for the implied *this pointer does not apply. +The warning is hidden by default, but can be displayed as described in the section on Enabling extra warnings. +

      + +

      +Consider: +

      + +
      +struct RQ {
      +  void m1(int x) &;
      +  void m2(int x) &&;
      +};
      +
      + +

      +The only wrapped method will be the lvalue ref-qualified method m1 +and if SWIG is run with the -Wextra command-line option, the following warning will be issued indicating m2 is not wrapped: +

      + +
      +
      +example.i:7: Warning 405: Method with rvalue ref-qualifier m2(int) && ignored.
      +
      +
      + +

      +If you unignore the method as follows, wrappers for m2 will be generated: +

      + +
      +%feature("ignore", "0") RQ::m2(int x) &&;
      +struct RQ {
      +  void m1(int x) &;
      +  void m2(int x) &&;
      +};
      +
      + +

      +Inspection of the generated C++ code, will show that std::move is used on the instance +of the RQ * class: +

      + +
      +  RQ *arg1 = (RQ *) 0 ;
      +  int arg2 ;
      +
      +  arg1 = ...marshalled from target language...
      +  arg2 = ...marshalled from target language...
      +
      +  std::move(*arg1).m2(arg2);
      +
      + +

      +This will compile but when run, the move effects may not be what you want. +As stated earlier, rvalue ref-qualifiers aren't really applicable outside the world of C++. +However, if you really know what you are doing, full control over the call to the method is +possible via the low-level "action" feature. +This feature completely replaces the call to the underlying function, that is, the last line in the snippet of code above. +

      + +
      +%feature("ignore", "0") RQ::m2(int x) &&;
      +%feature("action") RQ::m2(int x) && %{
      +  RQ().m2(arg2);
      +%}
      +struct RQ {
      +  void m1(int x) &;
      +  void m2(int x) &&;
      +};
      +
      + +

      +resulting in: +

      + +
      +  RQ *arg1 = (RQ *) 0 ;
      +  int arg2 ;
      +
      +  arg1 = ...marshalled from target language...
      +  arg2 = ...marshalled from target language...
      +
      +  RQ().m2(arg2);
      +
      + +

      +Compatibility note: SWIG-4.0.0 was the first version to support ref-qualifiers. +

      7.3 Standard library changes

      @@ -1177,5 +1276,6 @@ Phew, that is a lot of hard work to get a callback working. You could just go with the more attractive option of just using double as the return type in the function declaration instead of result_of!

      + diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 3d9f6fd3b..b879eaa04 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -310,6 +310,7 @@
    • Exception specifications and noexcept
    • Control and query object alignment
    • Attributes +
    • Methods with ref-qualifiers
  • Standard library changes
      diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index 57da73d31..f64de15e3 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -2409,8 +2409,8 @@ the first renaming rule found on a depth-first traversal of the class hierarchy is used. -
    • The name matching rules strictly follow member qualification rules. -For example, if you have a class like this:

      +
    • The name matching rules strictly follow member qualifier rules. +For example, if you have a class and member with a member that is const qualified like this:

      @@ -2434,7 +2434,7 @@ the declaration
       

      -will not apply as there is no unqualified member bar(). The following will apply as +will not apply as there is no unqualified member bar(). The following will apply the rename as the qualifier matches correctly:

      @@ -2444,6 +2444,26 @@ the qualifier matches correctly: +

      +Similarly for combinations of cv-qualifiers and ref-qualifiers, all the qualifiers must be specified to match correctly: +

      + +
      +
      +%rename(name) Jam::bar();          // will not match
      +%rename(name) Jam::bar() &;        // will not match
      +%rename(name) Jam::bar() const;    // will not match
      +%rename(name) Jam::bar() const &;  // ok, will match
      +
      +class Jam {
      +public:
      +  ...
      +  void bar() const &;
      +  ...
      +};
      +
      +
      +

      An often overlooked C++ feature is that classes can define two different overloaded members that differ only in their qualifiers, like this: @@ -2476,7 +2496,7 @@ For example we can give them separate names in the target language:

      Similarly, if you merely wanted to ignore one of the declarations, use %ignore -with the full qualification. For example, the following directive +with the full qualifier. For example, the following directive would tell SWIG to ignore the const version of bar() above:

      diff --git a/Doc/Manual/Typemaps.html b/Doc/Manual/Typemaps.html index f274c9293..eeabdd89a 100644 --- a/Doc/Manual/Typemaps.html +++ b/Doc/Manual/Typemaps.html @@ -4021,7 +4021,7 @@ struct X { Forced inclusion of fragments can be used as a replacement for code insertion block, ensuring the code block is only generated once. Consider the contents of FileA.i below which first uses a code insertion block and then a forced fragment inclusion to generate code: -

      +

       // FileA.i
      @@ -4058,7 +4058,7 @@ The resulting code in the wrappers for FileB.i is:
       

      A note of caution must be mentioned when using %fragment forced inclusion or code insertion blocks with %import. If %import is used instead: -

      +

      
      From c9d425604c58a9c862b562ffffd260f6647b08c2 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Sat, 26 Aug 2017 14:00:44 +0100
      Subject: [PATCH 07/15] Re-organise parser grammar for declarator and
       initializer rules
      
      Step 1 to make these closer to the definitions used in the standard.
      The initializer rule should not include qualifiers and exception specification.
      
      - split cpp_const into add qualifiers_exception_specification and empty rules
      - simplify initializer to use new qualifiers_exception_specification rule
      ---
       Source/CParse/parser.y | 37 +++++++++++++------------------------
       1 file changed, 13 insertions(+), 24 deletions(-)
      
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index 3e0fd3282..4c73b8a25 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -1591,7 +1591,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
       
       /* Misc */
       %type        identifier;
      -%type     initializer cpp_const exception_specification cv_ref_qualifier;
      +%type     initializer cpp_const exception_specification cv_ref_qualifier qualifiers_exception_specification;
       %type        storage_class extern_string;
       %type        parms  ptail rawparms varargs_parms ;
       %type        templateparameters templateparameterstail;
      @@ -3268,38 +3268,22 @@ c_decl_tail    : SEMI {
                      }
                     ;
       
      -initializer   : def_args { 
      -                   $$ = $1; 
      +initializer   : def_args {
      +                   $$ = $1;
                          $$.qualifier = 0;
                          $$.refqualifier = 0;
       		   $$.throws = 0;
       		   $$.throwf = 0;
       		   $$.nexcept = 0;
                     }
      -              | cv_ref_qualifier def_args {
      -                   $$ = $2; 
      -		   $$.qualifier = $1.qualifier;
      -		   $$.refqualifier = $1.refqualifier;
      -		   $$.throws = 0;
      -		   $$.throwf = 0;
      -		   $$.nexcept = 0;
      -	      }
      -              | exception_specification def_args { 
      -		   $$ = $2; 
      -                   $$.qualifier = 0;
      -                   $$.refqualifier = 0;
      +              | qualifiers_exception_specification def_args {
      +                   $$ = $2;
      +                   $$.qualifier = $1.qualifier;
      +                   $$.refqualifier = $1.refqualifier;
       		   $$.throws = $1.throws;
       		   $$.throwf = $1.throwf;
       		   $$.nexcept = $1.nexcept;
                     }
      -              | cv_ref_qualifier exception_specification def_args {
      -                   $$ = $3; 
      -                   $$.qualifier = $1.qualifier;
      -		   $$.refqualifier = $1.refqualifier;
      -		   $$.throws = $2.throws;
      -		   $$.throwf = $2.throwf;
      -		   $$.nexcept = $2.nexcept;
      -              }
                     ;
       
       cpp_alternate_rettype : primitive_type { $$ = $1; }
      @@ -6688,7 +6672,7 @@ exception_specification : THROW LPAREN parms RPAREN {
       	       }
       	       ;	
       
      -cpp_const      : cv_ref_qualifier {
      +qualifiers_exception_specification : cv_ref_qualifier {
                           $$.throws = 0;
                           $$.throwf = 0;
                           $$.nexcept = 0;
      @@ -6705,6 +6689,11 @@ cpp_const      : cv_ref_qualifier {
                           $$.qualifier = $1.qualifier;
                           $$.refqualifier = $1.refqualifier;
                      }
      +               ;
      +
      +cpp_const      : qualifiers_exception_specification {
      +                    $$ = $1;
      +               }
                      | empty { 
                           $$.throws = 0;
                           $$.throwf = 0;
      
      From 8227c02267b1bc54e88c714251e2052260810650 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Sat, 26 Aug 2017 23:23:54 +0100
      Subject: [PATCH 08/15] Re-organise parser grammar for initializer rules
      
      Simply split initializer into const_cpp and initializer
      ---
       Source/CParse/parser.y | 73 +++++++++++++++++-------------------------
       1 file changed, 30 insertions(+), 43 deletions(-)
      
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index 4c73b8a25..b999a3796 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -3090,7 +3090,7 @@ c_declaration   : c_decl {
          A C global declaration of some kind (may be variable, function, typedef, etc.)
          ------------------------------------------------------------ */
       
      -c_decl  : storage_class type declarator initializer c_decl_tail {
      +c_decl  : storage_class type declarator cpp_const initializer c_decl_tail {
       	      String *decl = $3.type;
                     $$ = new_node("cdecl");
       	      if ($4.qualifier)
      @@ -3101,26 +3101,26 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
       	      Setattr($$,"name",$3.id);
       	      Setattr($$,"decl",decl);
       	      Setattr($$,"parms",$3.parms);
      -	      Setattr($$,"value",$4.val);
      +	      Setattr($$,"value",$5.val);
       	      Setattr($$,"throws",$4.throws);
       	      Setattr($$,"throw",$4.throwf);
       	      Setattr($$,"noexcept",$4.nexcept);
      -	      if ($4.val && $4.type) {
      +	      if ($5.val && $5.type) {
       		/* store initializer type as it might be different to the declared type */
      -		SwigType *valuetype = NewSwigType($4.type);
      +		SwigType *valuetype = NewSwigType($5.type);
       		if (Len(valuetype) > 0)
       		  Setattr($$,"valuetype",valuetype);
       		else
       		  Delete(valuetype);
       	      }
      -	      if (!$5) {
      +	      if (!$6) {
       		if (Len(scanner_ccode)) {
       		  String *code = Copy(scanner_ccode);
       		  Setattr($$,"code",code);
       		  Delete(code);
       		}
       	      } else {
      -		Node *n = $5;
      +		Node *n = $6;
       		/* Inherit attributes */
       		while (n) {
       		  String *type = Copy($2);
      @@ -3130,8 +3130,8 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
       		  Delete(type);
       		}
       	      }
      -	      if ($4.bitfield) {
      -		Setattr($$,"bitfield", $4.bitfield);
      +	      if ($5.bitfield) {
      +		Setattr($$,"bitfield", $5.bitfield);
       	      }
       
       	      if ($3.id) {
      @@ -3146,18 +3146,18 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
       		      String *lstr = Swig_scopename_last($3.id);
       		      Setattr($$, "name", lstr);
       		      Delete(lstr);
      -		      set_nextSibling($$, $5);
      +		      set_nextSibling($$, $6);
       		    } else {
       		      Delete($$);
      -		      $$ = $5;
      +		      $$ = $6;
       		    }
       		    Delete(p);
       		  } else {
       		    Delete($$);
      -		    $$ = $5;
      +		    $$ = $6;
       		  }
       		} else {
      -		  set_nextSibling($$, $5);
      +		  set_nextSibling($$, $6);
       		}
       	      } else {
       		Swig_error(cparse_file, cparse_line, "Missing symbol name for global declaration\n");
      @@ -3166,7 +3166,7 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
                  }
                  /* Alternate function syntax introduced in C++11:
                     auto funcName(int x, int y) -> int; */
      -           | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype initializer c_decl_tail {
      +           | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype cpp_const initializer c_decl_tail {
                     $$ = new_node("cdecl");
       	      if ($4.qualifier) SwigType_push($3.type, $4.qualifier);
       	      Setattr($$,"refqualifier",$4.refqualifier);
      @@ -3179,14 +3179,14 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
       	      Setattr($$,"throws",$4.throws);
       	      Setattr($$,"throw",$4.throwf);
       	      Setattr($$,"noexcept",$4.nexcept);
      -	      if (!$8) {
      +	      if (!$9) {
       		if (Len(scanner_ccode)) {
       		  String *code = Copy(scanner_ccode);
       		  Setattr($$,"code",code);
       		  Delete(code);
       		}
       	      } else {
      -		Node *n = $8;
      +		Node *n = $9;
       		while (n) {
       		  String *type = Copy($6);
       		  Setattr(n,"type",type);
      @@ -3207,18 +3207,18 @@ c_decl  : storage_class type declarator initializer c_decl_tail {
       		    String *lstr = Swig_scopename_last($3.id);
       		    Setattr($$,"name",lstr);
       		    Delete(lstr);
      -		    set_nextSibling($$, $8);
      +		    set_nextSibling($$, $9);
       		  } else {
       		    Delete($$);
      -		    $$ = $8;
      +		    $$ = $9;
       		  }
       		  Delete(p);
       		} else {
       		  Delete($$);
      -		  $$ = $8;
      +		  $$ = $9;
       		}
       	      } else {
      -		set_nextSibling($$, $8);
      +		set_nextSibling($$, $9);
       	      }
                  }
                  ;
      @@ -3229,28 +3229,28 @@ c_decl_tail    : SEMI {
                          $$ = 0;
                          Clear(scanner_ccode); 
                      }
      -               | COMMA declarator initializer c_decl_tail {
      +               | COMMA declarator cpp_const initializer c_decl_tail {
       		 $$ = new_node("cdecl");
       		 if ($3.qualifier) SwigType_push($2.type,$3.qualifier);
       		 Setattr($$,"refqualifier",$3.refqualifier);
       		 Setattr($$,"name",$2.id);
       		 Setattr($$,"decl",$2.type);
       		 Setattr($$,"parms",$2.parms);
      -		 Setattr($$,"value",$3.val);
      +		 Setattr($$,"value",$4.val);
       		 Setattr($$,"throws",$3.throws);
       		 Setattr($$,"throw",$3.throwf);
       		 Setattr($$,"noexcept",$3.nexcept);
      -		 if ($3.bitfield) {
      -		   Setattr($$,"bitfield", $3.bitfield);
      +		 if ($4.bitfield) {
      +		   Setattr($$,"bitfield", $4.bitfield);
       		 }
      -		 if (!$4) {
      +		 if (!$5) {
       		   if (Len(scanner_ccode)) {
       		     String *code = Copy(scanner_ccode);
       		     Setattr($$,"code",code);
       		     Delete(code);
       		   }
       		 } else {
      -		   set_nextSibling($$,$4);
      +		   set_nextSibling($$, $5);
       		 }
       	       }
                      | LBRACE { 
      @@ -3270,19 +3270,6 @@ c_decl_tail    : SEMI {
       
       initializer   : def_args {
                          $$ = $1;
      -                   $$.qualifier = 0;
      -                   $$.refqualifier = 0;
      -		   $$.throws = 0;
      -		   $$.throwf = 0;
      -		   $$.nexcept = 0;
      -              }
      -              | qualifiers_exception_specification def_args {
      -                   $$ = $2;
      -                   $$.qualifier = $1.qualifier;
      -                   $$.refqualifier = $1.refqualifier;
      -		   $$.throws = $1.throws;
      -		   $$.throwf = $1.throwf;
      -		   $$.nexcept = $1.nexcept;
                     }
                     ;
       
      @@ -3425,7 +3412,7 @@ c_enum_decl :  storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBR
       		    Namespaceprefix = Swig_symbol_qualifiedscopename(0);
       		  }
                      }
      -	       | storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBRACE declarator initializer c_decl_tail {
      +	       | storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBRACE declarator cpp_const initializer c_decl_tail {
       		 Node *n;
       		 SwigType *ty = 0;
       		 String   *unnamed = 0;
      @@ -3472,8 +3459,8 @@ c_enum_decl :  storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBR
       		   SetFlag(n,"unnamedinstance");
       		   Delete(cty);
                        }
      -		 if ($10) {
      -		   Node *p = $10;
      +		 if ($11) {
      +		   Node *p = $11;
       		   set_nextSibling(n,p);
       		   while (p) {
       		     SwigType *cty = Copy(ty);
      @@ -3981,12 +3968,12 @@ cpp_class_decl  : storage_class cpptype idcolon inherit LBRACE {
                    ;
       
       cpp_opt_declarators :  SEMI { $$ = 0; }
      -                    |  declarator initializer c_decl_tail {
      +                    |  declarator cpp_const initializer c_decl_tail {
                               $$ = new_node("cdecl");
                               Setattr($$,"name",$1.id);
                               Setattr($$,"decl",$1.type);
                               Setattr($$,"parms",$1.parms);
      -			set_nextSibling($$,$3);
      +			set_nextSibling($$, $4);
                           }
                           ;
       /* ------------------------------------------------------------
      
      From 0e50ef30b1aef7e11e3e6e42948593001666961a Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Sat, 26 Aug 2017 23:39:34 +0100
      Subject: [PATCH 09/15] Alternate function syntax parsing improvement
      
      This was incorrectly accepting qualifiers and exception specifications
      in the wrong place.
      ---
       Source/CParse/parser.y | 12 ++++++++++--
       1 file changed, 10 insertions(+), 2 deletions(-)
      
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index b999a3796..f9dc6b32f 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -1629,7 +1629,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
       %type      lambda_introducer lambda_body;
       %type        lambda_tail;
       %type      optional_constant_directive;
      -%type       virt_specifier_seq;
      +%type       virt_specifier_seq virt_specifier_seq_opt;
       
       %%
       
      @@ -3166,7 +3166,7 @@ c_decl  : storage_class type declarator cpp_const initializer c_decl_tail {
                  }
                  /* Alternate function syntax introduced in C++11:
                     auto funcName(int x, int y) -> int; */
      -           | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype cpp_const initializer c_decl_tail {
      +           | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype virt_specifier_seq_opt initializer c_decl_tail {
                     $$ = new_node("cdecl");
       	      if ($4.qualifier) SwigType_push($3.type, $4.qualifier);
       	      Setattr($$,"refqualifier",$4.refqualifier);
      @@ -6627,6 +6627,14 @@ virt_specifier_seq : OVERRIDE {
       	       }
                      ;
       
      +virt_specifier_seq_opt : virt_specifier_seq {
      +                   $$ = 0;
      +               }
      +               | empty {
      +                   $$ = 0;
      +               }
      +               ;
      +
       exception_specification : THROW LPAREN parms RPAREN {
                           $$.throws = $3;
                           $$.throwf = NewString("1");
      
      From 950edc1c000daf15846eeb878111354ee3c293d7 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Tue, 29 Aug 2017 21:11:26 +0100
      Subject: [PATCH 10/15] Add support for conversion operators with
       ref-qualifiers
      
      ---
       Examples/test-suite/cpp11_ref_qualifiers.i        | 15 +++++++++++++++
       .../java/cpp11_ref_qualifiers_runme.java          |  9 +++++++++
       .../python/cpp11_ref_qualifiers_runme.py          |  8 ++++++++
       Source/CParse/parser.y                            | 11 ++++++++---
       4 files changed, 40 insertions(+), 3 deletions(-)
      
      diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i
      index 2115843a3..7e9f0e170 100644
      --- a/Examples/test-suite/cpp11_ref_qualifiers.i
      +++ b/Examples/test-suite/cpp11_ref_qualifiers.i
      @@ -74,3 +74,18 @@ struct Renames {
         string S3(int i) const & { return string(); }
       };
       %}
      +
      +// Conversion operators
      +%rename(StringConvertCopy) operator string() &;
      +%rename(StringConvertMove) operator string() &&;
      +%feature("ignore", "0") operator string() &&; // unignore as it is ignored by default
      +
      +%inline %{
      +struct ConversionOperators {
      +  virtual operator string() & { return string(); }
      +  virtual operator string() && { return std::move(string()); }
      +};
      +struct ConversionOperators2 {
      +  virtual operator string() && { return std::move(string()); }
      +};
      +%}
      diff --git a/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java
      index bbe6be8e3..4755f8d1f 100644
      --- a/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java
      +++ b/Examples/test-suite/java/cpp11_ref_qualifiers_runme.java
      @@ -42,6 +42,15 @@ public class cpp11_ref_qualifiers_runme {
           r.SS1(0);
           r.SS2(0);
           r.SS3(0);
      +
      +    // Conversion operators
      +    String s = null;
      +    ConversionOperators co = new ConversionOperators();
      +    s = co.StringConvertCopy();
      +    s = co.StringConvertMove();
      +
      +    ConversionOperators2 co2 = new ConversionOperators2();
      +    s = co2.StringConvertMove();
         }
       }
       
      diff --git a/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py
      index 47c474218..d3aa98c47 100644
      --- a/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py
      +++ b/Examples/test-suite/python/cpp11_ref_qualifiers_runme.py
      @@ -35,3 +35,11 @@ r.RR3()
       r.SS1(0)
       r.SS2(0)
       r.SS3(0)
      +
      +# Conversion operators
      +co = cpp11_ref_qualifiers.ConversionOperators()
      +s = co.StringConvertCopy()
      +s = co.StringConvertMove()
      +
      +co2 = cpp11_ref_qualifiers.ConversionOperators2()
      +s = co2.StringConvertMove()
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index f9dc6b32f..a982ce011 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -4656,6 +4656,7 @@ cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN p
       		 if ($8.qualifier) {
       		   SwigType_push($4,$8.qualifier);
       		 }
      +		 Setattr($$,"refqualifier",$8.refqualifier);
       		 Setattr($$,"decl",$4);
       		 Setattr($$,"parms",$6);
       		 Setattr($$,"conversion_operator","1");
      @@ -4673,6 +4674,7 @@ cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN p
       		 if ($8.qualifier) {
       		   SwigType_push(decl,$8.qualifier);
       		 }
      +		 Setattr($$,"refqualifier",$8.refqualifier);
       		 Setattr($$,"decl",decl);
       		 Setattr($$,"parms",$6);
       		 Setattr($$,"conversion_operator","1");
      @@ -4690,6 +4692,7 @@ cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN p
       		 if ($8.qualifier) {
       		   SwigType_push(decl,$8.qualifier);
       		 }
      +		 Setattr($$,"refqualifier",$8.refqualifier);
       		 Setattr($$,"decl",decl);
       		 Setattr($$,"parms",$6);
       		 Setattr($$,"conversion_operator","1");
      @@ -4709,6 +4712,7 @@ cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN p
       		 if ($9.qualifier) {
       		   SwigType_push(decl,$9.qualifier);
       		 }
      +		 Setattr($$,"refqualifier",$9.refqualifier);
       		 Setattr($$,"decl",decl);
       		 Setattr($$,"parms",$7);
       		 Setattr($$,"conversion_operator","1");
      @@ -4725,6 +4729,7 @@ cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN p
       		if ($7.qualifier) {
       		  SwigType_push(t,$7.qualifier);
       		}
      +		 Setattr($$,"refqualifier",$7.refqualifier);
       		Setattr($$,"decl",t);
       		Setattr($$,"parms",$5);
       		Setattr($$,"conversion_operator","1");
      @@ -4819,7 +4824,7 @@ cpp_vend       : cpp_const SEMI {
                            Clear(scanner_ccode);
                            $$.val = 0;
                            $$.qualifier = $1.qualifier;
      -                     $$.refqualifier = 0;
      +                     $$.refqualifier = $1.refqualifier;
                            $$.bitfield = 0;
                            $$.throws = $1.throws;
                            $$.throwf = $1.throwf;
      @@ -4829,7 +4834,7 @@ cpp_vend       : cpp_const SEMI {
                            Clear(scanner_ccode);
                            $$.val = $3.val;
                            $$.qualifier = $1.qualifier;
      -                     $$.refqualifier = 0;
      +                     $$.refqualifier = $1.refqualifier;
                            $$.bitfield = 0;
                            $$.throws = $1.throws; 
                            $$.throwf = $1.throwf; 
      @@ -4839,7 +4844,7 @@ cpp_vend       : cpp_const SEMI {
                            skip_balanced('{','}');
                            $$.val = 0;
                            $$.qualifier = $1.qualifier;
      -                     $$.refqualifier = 0;
      +                     $$.refqualifier = $1.refqualifier;
                            $$.bitfield = 0;
                            $$.throws = $1.throws; 
                            $$.throwf = $1.throwf; 
      
      From 7e4717320b73dd68f00a5709f2ec346ec53b7cc2 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Wed, 30 Aug 2017 06:57:51 +0100
      Subject: [PATCH 11/15] Add error for constructors, destructors, static methods
       declared with qualifiers
      
      SWIG parses a superset of valid C++ declarations. These ill-formed declarations
      were previously successfully parsed but now result an error message.
      ---
       .../errors/cpp_invalid_qualifiers.i           | 43 +++++++++++++++++++
       .../errors/cpp_invalid_qualifiers.stderr      | 20 +++++++++
       Source/CParse/parser.y                        | 26 ++++++++++-
       3 files changed, 88 insertions(+), 1 deletion(-)
       create mode 100644 Examples/test-suite/errors/cpp_invalid_qualifiers.i
       create mode 100644 Examples/test-suite/errors/cpp_invalid_qualifiers.stderr
      
      diff --git a/Examples/test-suite/errors/cpp_invalid_qualifiers.i b/Examples/test-suite/errors/cpp_invalid_qualifiers.i
      new file mode 100644
      index 000000000..fd3b36332
      --- /dev/null
      +++ b/Examples/test-suite/errors/cpp_invalid_qualifiers.i
      @@ -0,0 +1,43 @@
      +%module cpp_invalid_qualifiers
      +
      +// Constructors, destructors and static methods cannot have qualifiers
      +struct A {
      +  ~A() const;
      +};
      +struct B {
      +  virtual ~B() const;
      +};
      +struct C {
      +  ~C() &;
      +};
      +struct D {
      +  virtual ~D() &;
      +};
      +struct E {
      +  ~E() &&;
      +};
      +struct F {
      +  virtual ~F() &&;
      +};
      +
      +struct J {
      +  J() const;
      +  J(int) const;
      +};
      +struct K {
      +  K() &;
      +  K(int) &;
      +};
      +struct L {
      +  L() &&;
      +  L(int) &&;
      +};
      +
      +struct M {
      +  static void m1() const;
      +  static void m2() &;
      +  thread_local static void m3() &&;
      +  static auto m4() const -> int;
      +  static auto m5() & -> int;
      +  static auto m6() && -> int;
      +};
      diff --git a/Examples/test-suite/errors/cpp_invalid_qualifiers.stderr b/Examples/test-suite/errors/cpp_invalid_qualifiers.stderr
      new file mode 100644
      index 000000000..7b3e442eb
      --- /dev/null
      +++ b/Examples/test-suite/errors/cpp_invalid_qualifiers.stderr
      @@ -0,0 +1,20 @@
      +cpp_invalid_qualifiers.i:5: Error: Destructor ~A() const cannot have a qualifier.
      +cpp_invalid_qualifiers.i:8: Error: Destructor ~B() const cannot have a qualifier.
      +cpp_invalid_qualifiers.i:11: Error: Destructor ~C() & cannot have a qualifier.
      +cpp_invalid_qualifiers.i:14: Error: Destructor ~D() & cannot have a qualifier.
      +cpp_invalid_qualifiers.i:17: Error: Destructor ~E() && cannot have a qualifier.
      +cpp_invalid_qualifiers.i:20: Error: Destructor ~F() && cannot have a qualifier.
      +cpp_invalid_qualifiers.i:24: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:25: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:28: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:29: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:32: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:33: Error: Constructor cannot have a qualifier.
      +cpp_invalid_qualifiers.i:37: Error: Static function m1() const cannot have a qualifier.
      +cpp_invalid_qualifiers.i:38: Error: Static function m2() & cannot have a qualifier.
      +cpp_invalid_qualifiers.i:39: Error: Static function m3() && cannot have a qualifier.
      +cpp_invalid_qualifiers.i:39: Warning 405: Method with rvalue ref-qualifier m3() && ignored.
      +cpp_invalid_qualifiers.i:40: Error: Static function m4() const cannot have a qualifier.
      +cpp_invalid_qualifiers.i:41: Error: Static function m5() & cannot have a qualifier.
      +cpp_invalid_qualifiers.i:42: Error: Static function m6() && cannot have a qualifier.
      +cpp_invalid_qualifiers.i:42: Warning 405: Method with rvalue ref-qualifier m6() && ignored.
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index a982ce011..f88eb5f60 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -3163,6 +3163,9 @@ c_decl  : storage_class type declarator cpp_const initializer c_decl_tail {
       		Swig_error(cparse_file, cparse_line, "Missing symbol name for global declaration\n");
       		$$ = 0;
       	      }
      +
      +	      if ($4.qualifier && $1 && Strstr($1, "static"))
      +		Swig_error(cparse_file, cparse_line, "Static function %s cannot have a qualifier.\n", Swig_name_decl($$));
                  }
                  /* Alternate function syntax introduced in C++11:
                     auto funcName(int x, int y) -> int; */
      @@ -3220,6 +3223,9 @@ c_decl  : storage_class type declarator cpp_const initializer c_decl_tail {
       	      } else {
       		set_nextSibling($$, $9);
       	      }
      +
      +	      if ($4.qualifier && $1 && Strstr($1, "static"))
      +		Swig_error(cparse_file, cparse_line, "Static function %s cannot have a qualifier.\n", Swig_name_decl($$));
                  }
                  ;
       
      @@ -4610,6 +4616,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
       	       Setattr($$,"noexcept",$6.nexcept);
       	       if ($6.val)
       	         Setattr($$,"value",$6.val);
      +	       if ($6.qualifier)
      +		 Swig_error(cparse_file, cparse_line, "Destructor %s %s cannot have a qualifier.\n", Swig_name_decl($$), SwigType_str($6.qualifier, 0));
       	       add_symbols($$);
       	      }
       
      @@ -4639,7 +4647,8 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
       		  Setattr($$,"decl",decl);
       		  Delete(decl);
       		}
      -
      +		if ($7.qualifier)
      +		  Swig_error(cparse_file, cparse_line, "Destructor %s %s cannot have a qualifier.\n", Swig_name_decl($$), SwigType_str($7.qualifier, 0));
       		add_symbols($$);
       	      }
                     ;
      @@ -4800,6 +4809,9 @@ cpp_swig_directive: pragma_directive { $$ = $1; }
       cpp_end        : cpp_const SEMI {
       	            Clear(scanner_ccode);
       		    $$.val = 0;
      +		    $$.qualifier = $1.qualifier;
      +		    $$.refqualifier = $1.refqualifier;
      +		    $$.bitfield = 0;
       		    $$.throws = $1.throws;
       		    $$.throwf = $1.throwf;
       		    $$.nexcept = $1.nexcept;
      @@ -4807,6 +4819,9 @@ cpp_end        : cpp_const SEMI {
                      | cpp_const EQUAL default_delete SEMI {
       	            Clear(scanner_ccode);
       		    $$.val = $3.val;
      +		    $$.qualifier = $1.qualifier;
      +		    $$.refqualifier = $1.refqualifier;
      +		    $$.bitfield = 0;
       		    $$.throws = $1.throws;
       		    $$.throwf = $1.throwf;
       		    $$.nexcept = $1.nexcept;
      @@ -4814,6 +4829,9 @@ cpp_end        : cpp_const SEMI {
                      | cpp_const LBRACE { 
       		    skip_balanced('{','}'); 
       		    $$.val = 0;
      +		    $$.qualifier = $1.qualifier;
      +		    $$.refqualifier = $1.refqualifier;
      +		    $$.bitfield = 0;
       		    $$.throws = $1.throws;
       		    $$.throwf = $1.throwf;
       		    $$.nexcept = $1.nexcept;
      @@ -6710,6 +6728,8 @@ ctor_end       : cpp_const ctor_initializer SEMI {
       		    $$.throws = $1.throws;
       		    $$.throwf = $1.throwf;
       		    $$.nexcept = $1.nexcept;
      +                    if ($1.qualifier)
      +                      Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
                      }
                      | cpp_const ctor_initializer LBRACE { 
                           skip_balanced('{','}'); 
      @@ -6718,6 +6738,8 @@ ctor_end       : cpp_const ctor_initializer SEMI {
                           $$.throws = $1.throws;
                           $$.throwf = $1.throwf;
                           $$.nexcept = $1.nexcept;
      +                    if ($1.qualifier)
      +                      Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
                      }
                      | LPAREN parms RPAREN SEMI { 
                           Clear(scanner_ccode); 
      @@ -6750,6 +6772,8 @@ ctor_end       : cpp_const ctor_initializer SEMI {
                           $$.throws = $1.throws;
                           $$.throwf = $1.throwf;
                           $$.nexcept = $1.nexcept;
      +                    if ($1.qualifier)
      +                      Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
                      }
                      ;
       
      
      From eb68e4375dccfb337fad0896b4a5510c5515b3ad Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Tue, 5 Sep 2017 18:44:00 +0100
      Subject: [PATCH 12/15] Add support for member function pointers with
       ref-qualifiers
      
      ---
       Examples/test-suite/cpp11_ref_qualifiers.i  | 117 ++++++++++++++++++++
       Examples/test-suite/member_funcptr_galore.i |   2 +-
       Source/CParse/parser.y                      |  13 ++-
       Source/Swig/stype.c                         | 108 +++++++++++-------
       4 files changed, 195 insertions(+), 45 deletions(-)
      
      diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i
      index 7e9f0e170..781e52f23 100644
      --- a/Examples/test-suite/cpp11_ref_qualifiers.i
      +++ b/Examples/test-suite/cpp11_ref_qualifiers.i
      @@ -1,5 +1,11 @@
       %module cpp11_ref_qualifiers
       
      +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) ccextra2;
      +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) ccextra3;
      +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc2;
      +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc3;
      +%warnfilter(SWIGWARN_TYPEMAP_SWIGTYPELEAK_MSG) cc5;
      +
       %include 
       
       %ignore Host::h() const &;
      @@ -89,3 +95,114 @@ struct ConversionOperators2 {
         virtual operator string() && { return std::move(string()); }
       };
       %}
      +
      +%inline %{
      +struct Funcs {
      +  short FF(bool) { return 0; }
      +  short CC(bool) const & { return 0; }
      +};
      +
      +class MemberFuncPtrs
      +{
      +public:
      +  // member ref-qualified function pointers, unnamed parameters
      +  int aaa1(short (Funcs::*)(bool) &) const;
      +  int aaa2(short (Funcs::* const *&)(bool) &) const;
      +  int aaa3(short (Funcs::* *&)(bool) &) const;
      +  int aaa4(short (Funcs::* *const&)(bool) &) const;
      +  int aaa5(short (Funcs::* &)(bool) &) const;
      +  int aaa6(short (Funcs::* const)(bool) &) const;
      +  int aaa7(short (Funcs::* const&)(bool) &) const;
      +
      +  // member cv-qualified and ref-qualified function pointers, unnamed parameters
      +  int bbb1(short (Funcs::*)(bool) const &) const;
      +  int bbb2(short (Funcs::* const *&)(bool) const &) const;
      +  int bbb3(short (Funcs::* *&)(bool) const &) const;
      +  int bbb4(short (Funcs::* *const&)(bool) const &) const;
      +  int bbb5(short (Funcs::* &)(bool) const &) const;
      +  int bbb6(short (Funcs::* const)(bool) const &) const;
      +  int bbb7(short (Funcs::* const&)(bool) const &) const;
      +
      +  // member ref-qualified function pointers, named parameters
      +  int qqq1(short (Funcs::* qq1)(bool) &) const;
      +  int qqq2(short (Funcs::* const *& qq2)(bool) &) const;
      +  int qqq3(short (Funcs::* *& qq3)(bool) &) const;
      +  int qqq4(short (Funcs::* *const& qq4)(bool) &) const;
      +  int qqq5(short (Funcs::* & qq5)(bool) &) const;
      +  int qqq6(short (Funcs::* const qq6)(bool) &) const;
      +  int qqq7(short (Funcs::* const& qq7)(bool) &) const;
      +
      +  // member cv-qualified and ref-qualified function pointers, named parameters
      +  int rrr1(short (Funcs::* rr1)(bool) const &) const;
      +  int rrr2(short (Funcs::* const *& rr2)(bool) const &) const;
      +  int rrr3(short (Funcs::* *& rr3)(bool) const &) const;
      +  int rrr4(short (Funcs::* *const& rr4)(bool) const &) const;
      +  int rrr5(short (Funcs::* & rr5)(bool) const &) const;
      +  int rrr6(short (Funcs::* const rr6)(bool) const &) const;
      +  int rrr7(short (Funcs::* const& rr7)(bool) const &) const;
      +};
      +
      +// member ref-qualified function pointers, unnamed parameters
      +int MemberFuncPtrs::aaa1(short (Funcs::*)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa2(short (Funcs::* const *&)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa3(short (Funcs::* *&)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa4(short (Funcs::* *const&)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa5(short (Funcs::* &)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa6(short (Funcs::* const)(bool) &) const { return 0; }
      +int MemberFuncPtrs::aaa7(short (Funcs::* const&)(bool) &) const { return 0; }
      +
      +// member cv-qualified and ref-qualified function pointers, unnamed parameters
      +int MemberFuncPtrs::bbb1(short (Funcs::*)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb2(short (Funcs::* const *&)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb3(short (Funcs::* *&)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb4(short (Funcs::* *const&)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb5(short (Funcs::* &)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb6(short (Funcs::* const)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::bbb7(short (Funcs::* const&)(bool) const &) const { return 0; }
      +
      +// member ref-qualified function pointers, named parameters
      +int MemberFuncPtrs::qqq1(short (Funcs::* qq1)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq2(short (Funcs::* const *& qq2)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq3(short (Funcs::* *& qq3)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq4(short (Funcs::* *const& qq4)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq5(short (Funcs::* & qq5)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq6(short (Funcs::* const qq6)(bool) &) const { return 0; }
      +int MemberFuncPtrs::qqq7(short (Funcs::* const& qq7)(bool) &) const { return 0; }
      +
      +// member cv-qualified and ref-qualified function pointers, named parameters
      +int MemberFuncPtrs::rrr1(short (Funcs::* rr1)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr2(short (Funcs::* const *& rr2)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr3(short (Funcs::* *& rr3)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr4(short (Funcs::* *const& rr4)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr5(short (Funcs::* & rr5)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr6(short (Funcs::* const rr6)(bool) const &) const { return 0; }
      +int MemberFuncPtrs::rrr7(short (Funcs::* const& rr7)(bool) const &) const { return 0; }
      +
      +// member cv-qualified and ref-qualified pointer variables
      +short (Funcs::* cc1)(bool) const & = &Funcs::CC;
      +
      +short (Funcs::* const * ccextra2)(bool) const & = &cc1;
      +short (Funcs::* * ccextra3)(bool) const & = &cc1;
      +short (Funcs::* *const ccextra4)(bool) const & = &cc1;
      +
      +short (Funcs::* const *& cc2)(bool) const & = ccextra2;
      +short (Funcs::* *& cc3)(bool) const & = ccextra3;
      +short (Funcs::* *const& cc4)(bool) const & = ccextra4;
      +short (Funcs::* & cc5)(bool) const & = cc1;
      +short (Funcs::* const cc6)(bool) const & = &Funcs::CC;
      +short (Funcs::* const& cc7)(bool) const & = cc1;
      +%}
      +
      +%inline %{
      +
      +struct Funktions {
      +  int addByValue(const int &a, int b) const & { return a+b; }
      +  int * addByPointer(const int &a, int b) const & { static int val; val = a+b; return &val; }
      +  int & addByReference(const int &a, int b) const & { static int val; val = a+b; return val; }
      +};
      +
      +int call1(int (Funktions::*d)(const int &, int) const &, int a, int b) { Funktions f; return (f.*d)(a, b); }
      +//int call2(int * (Funktions::*d)(const int &, int) const &, int a, int b) { Funktions f; return *(f.*d)(a, b); }
      +//int call3(int & (Funktions::*d)(const int &, int) const &, int a, int b) { Funktions f; return (f.*d)(a, b); }
      +%}
      +%constant int (Funktions::*ADD_BY_VALUE)(const int &, int) const & = &Funktions::addByValue;
      diff --git a/Examples/test-suite/member_funcptr_galore.i b/Examples/test-suite/member_funcptr_galore.i
      index 01857ff1a..27c2f02a7 100644
      --- a/Examples/test-suite/member_funcptr_galore.i
      +++ b/Examples/test-suite/member_funcptr_galore.i
      @@ -161,7 +161,7 @@ public:
           int qqq7(short (Funcs::* const& qq7)(bool)) const;
       };
       
      -    // member const function pointers, unnamed parameters
      +// member const function pointers, unnamed parameters
       int MemberFuncPtrs::aaa1(short (Funcs::* )(bool) const) const { return 0; }
       int MemberFuncPtrs::aaa2(short (Funcs::* const *&)(bool) const) const { return 0; }
       int MemberFuncPtrs::aaa3(short (Funcs::* *& )(bool) const) const { return 0; }
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index f88eb5f60..9cf6f00c6 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -1897,10 +1897,10 @@ constant_directive :  CONSTANT identifier EQUAL definetype SEMI {
                      }
       	       /* Member const function pointers . eg.
       	         %constant short (Funcs::*pmf)(bool) const = &Funcs::F; */
      -	       | CONSTANT type direct_declarator LPAREN parms RPAREN CONST_QUAL def_args SEMI {
      +	       | CONSTANT type direct_declarator LPAREN parms RPAREN cv_ref_qualifier def_args SEMI {
       		 if (($8.type != T_ERROR) && ($8.type != T_SYMBOL)) {
       		   SwigType_add_function($2, $5);
      -		   SwigType_add_qualifier($2, "const");
      +		   SwigType_push($2, $7.qualifier);
       		   SwigType_push($2, $3.type);
       		   /* Sneaky callback function trick */
       		   if (SwigType_isfunction($2)) {
      @@ -5118,12 +5118,13 @@ parameter_declarator : declarator def_args {
                   }
       	    /* Member const function pointer parameters. eg.
       	      int f(short (Funcs::*parm)(bool) const); */
      -	    | direct_declarator LPAREN parms RPAREN CONST_QUAL {
      +	    | direct_declarator LPAREN parms RPAREN cv_ref_qualifier {
       	      SwigType *t;
       	      $$ = $1;
       	      t = NewStringEmpty();
       	      SwigType_add_function(t,$3);
      -	      SwigType_add_qualifier(t, "const");
      +	      if ($5.qualifier)
      +	        SwigType_push(t, $5.qualifier);
       	      if (!$$.have_parms) {
       		$$.parms = $3;
       		$$.have_parms = 1;
      @@ -5812,12 +5813,12 @@ direct_abstract_declarator : direct_abstract_declarator LBRACKET RBRACKET {
       		      $$.have_parms = 1;
       		    }
       		  }
      -                  | direct_abstract_declarator LPAREN parms RPAREN type_qualifier {
      +                  | direct_abstract_declarator LPAREN parms RPAREN cv_ref_qualifier {
       		    SwigType *t;
                           $$ = $1;
       		    t = NewStringEmpty();
                           SwigType_add_function(t,$3);
      -		    SwigType_push(t, $5);
      +		    SwigType_push(t, $5.qualifier);
       		    if (!$$.type) {
       		      $$.type = t;
       		    } else {
      diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c
      index 4b745b335..346731996 100644
      --- a/Source/Swig/stype.c
      +++ b/Source/Swig/stype.c
      @@ -544,10 +544,9 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
         String *element = 0;
         String *nextelement;
         String *forwardelement;
      -  String *member_const_function_element = 0;
      +  SwigType *member_function_qualifiers = 0;
         List *elements;
         int nelements, i;
      -  int member_const_function = 0;
       
         if (id) {
           /* stringify the id expanding templates, for example when the id is a fully qualified templated class name */
      @@ -578,14 +577,12 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
             forwardelement = 0;
           }
           if (SwigType_isqualifier(element)) {
      -      if (!member_const_function) {
      +      if (!member_function_qualifiers) {
       	DOH *q = 0;
       	q = SwigType_parm(element);
       	Insert(result, 0, " ");
       	Insert(result, 0, q);
       	Delete(q);
      -      } else {
      -        member_const_function = 0;
             }
           } else if (SwigType_ispointer(element)) {
             Insert(result, 0, "*");
      @@ -602,19 +599,27 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
      -      if (SwigType_isqualifier(nextelement)) {
      -	member_const_function_element = nextelement;
      -	member_const_function = 1;
      +      {
      +	String *next3elements = NewStringEmpty();
      +	int j;
      +	for (j = i + 1; j < i + 4 && j < nelements; j++) {
      +	  Append(next3elements, Getitem(elements, j));
      +	}
      +	if (SwigType_isfunction(next3elements))
      +	  member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements);
      +	Delete(next3elements);
             }
             Delete(q);
           } else if (SwigType_isreference(element)) {
      -      Insert(result, 0, "&");
      +      if (!member_function_qualifiers)
      +	Insert(result, 0, "&");
             if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
           } else if (SwigType_isrvalue_reference(element)) {
      -      Insert(result, 0, "&&");
      +      if (!member_function_qualifiers)
      +	Insert(result, 0, "&&");
             if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
      @@ -639,12 +644,13 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
       	  Append(result, ",");
             }
             Append(result, ")");
      -      if (member_const_function_element) {
      -	String *p = SwigType_str(member_const_function_element, 0);
      +      if (member_function_qualifiers) {
      +	String *p = SwigType_str(member_function_qualifiers, 0);
       	Append(result, " ");
       	Append(result, p);
       	Delete(p);
      -	member_const_function_element = 0;
      +	Delete(member_function_qualifiers);
      +	member_function_qualifiers = 0;
             }
             Delete(parms);
           } else {
      @@ -678,7 +684,7 @@ SwigType *SwigType_ltype(const SwigType *s) {
         int nelements, i;
         int firstarray = 1;
         int notypeconv = 0;
      -  int memberpointer = 0;
      +  int ignore_member_function_qualifiers = 0;
       
         result = NewStringEmpty();
         tc = Copy(s);
      @@ -705,6 +711,7 @@ SwigType *SwigType_ltype(const SwigType *s) {
             tc = td;
           }
         }
      +
         elements = SwigType_split(tc);
         nelements = Len(elements);
       
      @@ -714,18 +721,34 @@ SwigType *SwigType_ltype(const SwigType *s) {
           /* when we see a function, we need to preserve the following types */
           if (SwigType_isfunction(element)) {
             notypeconv = 1;
      +      ignore_member_function_qualifiers = 0;
           }
      -    if (SwigType_isqualifier(element)) {
      -      if (memberpointer)
      -	Append(result, element);
      -      /* otherwise ignore */
      +    if (ignore_member_function_qualifiers) {
      +      /* cv-qualifiers and ref-qualifiers up until the f() element have already been added */
      +    } else if (SwigType_isqualifier(element)) {
      +      /* swallow cv-qualifiers */
           } else if (SwigType_ispointer(element)) {
             Append(result, element);
             firstarray = 0;
           } else if (SwigType_ismemberpointer(element)) {
             Append(result, element);
      +      {
      +	String *next3elements = NewStringEmpty();
      +	int j;
      +	for (j = i + 1; j < i + 4 && j < nelements; j++) {
      +	  Append(next3elements, Getitem(elements, j));
      +	}
      +	if (SwigType_isfunction(next3elements)) {
      +	  SwigType *member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements);
      +	  /* compilers won't let us cast from a member function without qualifiers to one with qualifiers, so the qualifiers are kept in the ltype */
      +	  if (member_function_qualifiers)
      +	    Append(result, member_function_qualifiers);
      +	  Delete(member_function_qualifiers);
      +	  ignore_member_function_qualifiers = 1;
      +	}
      +	Delete(next3elements);
      +      }
             firstarray = 0;
      -      memberpointer = 1;
           } else if (SwigType_isreference(element)) {
             if (notypeconv) {
       	Append(result, element);
      @@ -764,13 +787,14 @@ SwigType *SwigType_ltype(const SwigType *s) {
       }
       
       /* -----------------------------------------------------------------------------
      - * SwigType_lstr(DOH *s, DOH *id)
      + * SwigType_lstr()
        *
        * Produces a type-string that is suitable as a lvalue in an expression.
        * That is, a type that can be freely assigned a value without violating
        * any C assignment rules.
        *
        *      -   Qualifiers such as 'const' and 'volatile' are stripped.
      + *          Except for member function cv-qualifiers and ref-qualifiers.
        *      -   Arrays are converted into a *single* pointer (i.e.,
        *          double [][] becomes double *).
        *      -   References are converted into a pointer.
      @@ -800,7 +824,7 @@ String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
         String *element = 0;
         String *nextelement;
         String *forwardelement;
      -  String *member_const_function_element = 0;
      +  String *member_function_qualifiers = 0;
         SwigType *td, *tc = 0;
         const SwigType *rs;
         List *elements;
      @@ -809,7 +833,6 @@ String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
         int firstarray = 1;
         int isreference = 0;
         int isfunction = 0;
      -  int member_const_function = 0;
       
         result = NewStringEmpty();
       
      @@ -858,15 +881,13 @@ String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
             forwardelement = 0;
           }
           if (SwigType_isqualifier(element)) {
      -      if (!member_const_function) {
      +      if (!member_function_qualifiers) {
       	DOH *q = 0;
       	q = SwigType_parm(element);
       	Insert(result, 0, " ");
       	Insert(result, 0, q);
       	Delete(q);
       	clear = 0;
      -      } else {
      -        member_const_function = 0;
             }
           } else if (SwigType_ispointer(element)) {
             Insert(result, 0, "*");
      @@ -880,32 +901,42 @@ String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
             Insert(result, 0, "::*");
             q = SwigType_parm(element);
             Insert(result, 0, q);
      -      Delete(q);
             if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
      -      if (SwigType_isqualifier(nextelement)) {
      -	member_const_function_element = nextelement;
      -	member_const_function = 1;
      +      {
      +	String *next3elements = NewStringEmpty();
      +	int j;
      +	for (j = i + 1; j < i + 4 && j < nelements; j++) {
      +	  Append(next3elements, Getitem(elements, j));
      +	}
      +	if (SwigType_isfunction(next3elements))
      +	  member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements);
      +	Delete(next3elements);
             }
             firstarray = 0;
      +      Delete(q);
           } else if (SwigType_isreference(element)) {
      -      Insert(result, 0, "&");
      +      if (!member_function_qualifiers) {
      +	Insert(result, 0, "&");
      +	if (!isfunction)
      +	  isreference = 1;
      +      }
             if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
      -      if (!isfunction)
      -	isreference = 1;
           } else if (SwigType_isrvalue_reference(element)) {
      -      Insert(result, 0, "&&");
      +      if (!member_function_qualifiers) {
      +	Insert(result, 0, "&&");
      +	if (!isfunction)
      +	  isreference = 1;
      +      }
             if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
      -      if (!isfunction)
      -	isreference = 1;
             clear = 0;
           } else if (SwigType_isarray(element)) {
             DOH *size;
      @@ -935,12 +966,13 @@ String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) {
             }
             Append(result, ")");
             Delete(parms);
      -      if (member_const_function_element) {
      -	String *p = SwigType_str(member_const_function_element, 0);
      +      if (member_function_qualifiers) {
      +	String *p = SwigType_str(member_function_qualifiers, 0);
       	Append(result, " ");
       	Append(result, p);
       	Delete(p);
      -	member_const_function_element = 0;
      +	Delete(member_function_qualifiers);
      +	member_function_qualifiers = 0;
       	clear = 0;
             }
             isfunction = 1;
      
      From 45c161dfcea94d5eaae65e753483a7c117506425 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Thu, 7 Sep 2017 06:58:01 +0100
      Subject: [PATCH 13/15] Fix wrapping of some member function pointer parameters
      
      Generated code did not compile if both cv-qualifiers and rvalue
      ref-qualifiers were present in the member function pointer.
      ---
       Examples/test-suite/cpp11_ref_qualifiers.i | 16 ++++++++++++++++
       Source/Swig/stype.c                        |  2 +-
       2 files changed, 17 insertions(+), 1 deletion(-)
      
      diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i
      index 781e52f23..237234e9c 100644
      --- a/Examples/test-suite/cpp11_ref_qualifiers.i
      +++ b/Examples/test-suite/cpp11_ref_qualifiers.i
      @@ -114,6 +114,8 @@ public:
         int aaa6(short (Funcs::* const)(bool) &) const;
         int aaa7(short (Funcs::* const&)(bool) &) const;
       
      +  int aaa8(short (Funcs::* const&)(bool) &&) const;
      +
         // member cv-qualified and ref-qualified function pointers, unnamed parameters
         int bbb1(short (Funcs::*)(bool) const &) const;
         int bbb2(short (Funcs::* const *&)(bool) const &) const;
      @@ -123,6 +125,8 @@ public:
         int bbb6(short (Funcs::* const)(bool) const &) const;
         int bbb7(short (Funcs::* const&)(bool) const &) const;
       
      +  int bbb8(short (Funcs::*)(bool) const &&) const;
      +
         // member ref-qualified function pointers, named parameters
         int qqq1(short (Funcs::* qq1)(bool) &) const;
         int qqq2(short (Funcs::* const *& qq2)(bool) &) const;
      @@ -132,6 +136,8 @@ public:
         int qqq6(short (Funcs::* const qq6)(bool) &) const;
         int qqq7(short (Funcs::* const& qq7)(bool) &) const;
       
      +  int qqq8(short (Funcs::* const& qq8)(bool) &&) const;
      +
         // member cv-qualified and ref-qualified function pointers, named parameters
         int rrr1(short (Funcs::* rr1)(bool) const &) const;
         int rrr2(short (Funcs::* const *& rr2)(bool) const &) const;
      @@ -140,6 +146,8 @@ public:
         int rrr5(short (Funcs::* & rr5)(bool) const &) const;
         int rrr6(short (Funcs::* const rr6)(bool) const &) const;
         int rrr7(short (Funcs::* const& rr7)(bool) const &) const;
      +
      +  int rrr8(short (Funcs::* rr1)(bool) const &&) const;
       };
       
       // member ref-qualified function pointers, unnamed parameters
      @@ -151,6 +159,8 @@ int MemberFuncPtrs::aaa5(short (Funcs::* &)(bool) &) const { return 0; }
       int MemberFuncPtrs::aaa6(short (Funcs::* const)(bool) &) const { return 0; }
       int MemberFuncPtrs::aaa7(short (Funcs::* const&)(bool) &) const { return 0; }
       
      +int MemberFuncPtrs::aaa8(short (Funcs::* const&)(bool) &&) const { return 0; }
      +
       // member cv-qualified and ref-qualified function pointers, unnamed parameters
       int MemberFuncPtrs::bbb1(short (Funcs::*)(bool) const &) const { return 0; }
       int MemberFuncPtrs::bbb2(short (Funcs::* const *&)(bool) const &) const { return 0; }
      @@ -160,6 +170,8 @@ int MemberFuncPtrs::bbb5(short (Funcs::* &)(bool) const &) const { return 0; }
       int MemberFuncPtrs::bbb6(short (Funcs::* const)(bool) const &) const { return 0; }
       int MemberFuncPtrs::bbb7(short (Funcs::* const&)(bool) const &) const { return 0; }
       
      +int MemberFuncPtrs::bbb8(short (Funcs::*)(bool) const &&) const { return 0; }
      +
       // member ref-qualified function pointers, named parameters
       int MemberFuncPtrs::qqq1(short (Funcs::* qq1)(bool) &) const { return 0; }
       int MemberFuncPtrs::qqq2(short (Funcs::* const *& qq2)(bool) &) const { return 0; }
      @@ -169,6 +181,8 @@ int MemberFuncPtrs::qqq5(short (Funcs::* & qq5)(bool) &) const { return 0; }
       int MemberFuncPtrs::qqq6(short (Funcs::* const qq6)(bool) &) const { return 0; }
       int MemberFuncPtrs::qqq7(short (Funcs::* const& qq7)(bool) &) const { return 0; }
       
      +int MemberFuncPtrs::qqq8(short (Funcs::* const& qq8)(bool) &&) const { return 0; }
      +
       // member cv-qualified and ref-qualified function pointers, named parameters
       int MemberFuncPtrs::rrr1(short (Funcs::* rr1)(bool) const &) const { return 0; }
       int MemberFuncPtrs::rrr2(short (Funcs::* const *& rr2)(bool) const &) const { return 0; }
      @@ -178,6 +192,8 @@ int MemberFuncPtrs::rrr5(short (Funcs::* & rr5)(bool) const &) const { return 0;
       int MemberFuncPtrs::rrr6(short (Funcs::* const rr6)(bool) const &) const { return 0; }
       int MemberFuncPtrs::rrr7(short (Funcs::* const& rr7)(bool) const &) const { return 0; }
       
      +int MemberFuncPtrs::rrr8(short (Funcs::* rr1)(bool) const &&) const { return 0; }
      +
       // member cv-qualified and ref-qualified pointer variables
       short (Funcs::* cc1)(bool) const & = &Funcs::CC;
       
      diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c
      index 346731996..364329d08 100644
      --- a/Source/Swig/stype.c
      +++ b/Source/Swig/stype.c
      @@ -620,7 +620,7 @@ String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) {
           } else if (SwigType_isrvalue_reference(element)) {
             if (!member_function_qualifiers)
       	Insert(result, 0, "&&");
      -      if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
      +      if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
       	Insert(result, 0, "(");
       	Append(result, ")");
             }
      
      From c4e280024fb1ed9881312dc997f36f6f3563f697 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Sat, 9 Sep 2017 23:46:14 +0100
      Subject: [PATCH 14/15] Add support for %typemap and member function pointers
       with qualifiers
      
      ---
       Examples/test-suite/common.mk                 |  1 +
       .../cpp11_ref_qualifiers_typemaps.i           | 74 +++++++++++++++++++
       .../cpp11_ref_qualifiers_typemaps_runme.java  | 39 ++++++++++
       Source/CParse/parser.y                        | 25 ++++++-
       4 files changed, 137 insertions(+), 2 deletions(-)
       create mode 100644 Examples/test-suite/cpp11_ref_qualifiers_typemaps.i
       create mode 100644 Examples/test-suite/java/cpp11_ref_qualifiers_typemaps_runme.java
      
      diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
      index 0d0a32c8c..4bd657c13 100644
      --- a/Examples/test-suite/common.mk
      +++ b/Examples/test-suite/common.mk
      @@ -563,6 +563,7 @@ CPP11_TEST_CASES += \
       	cpp11_raw_string_literals \
       	cpp11_ref_qualifiers \
       	cpp11_ref_qualifiers_rvalue_unignore \
      +	cpp11_ref_qualifiers_typemaps \
       	cpp11_result_of \
       	cpp11_rvalue_reference \
       	cpp11_rvalue_reference2 \
      diff --git a/Examples/test-suite/cpp11_ref_qualifiers_typemaps.i b/Examples/test-suite/cpp11_ref_qualifiers_typemaps.i
      new file mode 100644
      index 000000000..e9cce4bfb
      --- /dev/null
      +++ b/Examples/test-suite/cpp11_ref_qualifiers_typemaps.i
      @@ -0,0 +1,74 @@
      +%module cpp11_ref_qualifiers_typemaps
      +
      +%typemap(in) SWIGTYPE (CLASS::*) %{
      +  _this_will_fail_to_compile_if_used_
      +%}
      +
      +// typemaps to completely ignore the input parm and override it
      +%typemap(in) short (Funcs::*ff)(bool) const   %{ $1 = &Funcs::FF2; %}
      +%typemap(in) short (Funcs::*cc)(bool) &       %{ $1 = &Funcs::CC5; %}
      +%typemap(in) short (Funcs::*gg)(bool) const & %{ $1 = &Funcs::GG8; %}
      +%typemap(in) short (Funcs::*hh)(bool) &&      %{ $1 = &Funcs::HH11; %}
      +
      +%typemap(in) short (Funcs::*)(bool) const   %{ $1 = &Funcs::FF3; %}
      +%typemap(in) short (Funcs::*)(bool) &       %{ $1 = &Funcs::CC6; %}
      +%typemap(in) short (Funcs::*)(bool) const & %{ $1 = &Funcs::GG9; %}
      +%typemap(in) short (Funcs::*)(bool) &&      %{ $1 = &Funcs::HH12; %}
      +
      +%inline %{
      +struct Funcs {
      +  short FF1(bool) const { return 1; }
      +  short FF2(bool) const { return 2; }
      +  short FF3(bool) const { return 3; }
      +  short CC4(bool) & { return 4; }
      +  short CC5(bool) & { return 5; }
      +  short CC6(bool) & { return 6; }
      +  short GG7(bool) const & { return 7; }
      +  short GG8(bool) const & { return 8; }
      +  short GG9(bool) const & { return 9; }
      +  short HH10(bool) && { return 10; }
      +  short HH11(bool) && { return 11; }
      +  short HH12(bool) && { return 12; }
      +};
      +struct TypemapsNamedParms
      +{
      +  short fff(short (Funcs::*ff)(bool) const) {
      +    Funcs funcs;
      +    return (funcs.*ff)(true);
      +  }
      +  short ccc(short (Funcs::*cc)(bool) &) {
      +    Funcs funcs;
      +    return (funcs.*cc)(true);
      +  }
      +  short ggg(short (Funcs::*gg)(bool) const &) {
      +    Funcs funcs;
      +    return (funcs.*gg)(true);
      +  }
      +  short hhh(short (Funcs::*hh)(bool) &&) {
      +    return (Funcs().*hh)(true);
      +  }
      +};
      +struct TypemapsUnnamedParms
      +{
      +  short fff(short (Funcs::*f)(bool) const) {
      +    Funcs funcs;
      +    return (funcs.*f)(true);
      +  }
      +  short ccc(short (Funcs::*c)(bool) &) {
      +    Funcs funcs;
      +    return (funcs.*c)(true);
      +  }
      +  short ggg(short (Funcs::*g)(bool) const &) {
      +    Funcs funcs;
      +    return (funcs.*g)(true);
      +  }
      +  short hhh(short (Funcs::*h)(bool) &&) {
      +    return (Funcs().*h)(true);
      +  }
      +};
      +%}
      +
      +%constant short (Funcs::*FF1_MFP)(bool) const = &Funcs::FF1;
      +%constant short (Funcs::*CC4_MFP)(bool) & = &Funcs::CC4;
      +%constant short (Funcs::*GG7_MFP)(bool) const & = &Funcs::GG7;
      +%constant short (Funcs::*HH10_MFP)(bool) && = &Funcs::HH10;
      diff --git a/Examples/test-suite/java/cpp11_ref_qualifiers_typemaps_runme.java b/Examples/test-suite/java/cpp11_ref_qualifiers_typemaps_runme.java
      new file mode 100644
      index 000000000..8c6a21b15
      --- /dev/null
      +++ b/Examples/test-suite/java/cpp11_ref_qualifiers_typemaps_runme.java
      @@ -0,0 +1,39 @@
      +import cpp11_ref_qualifiers_typemaps.*;
      +
      +public class cpp11_ref_qualifiers_typemaps_runme {
      +  static {
      +    try {
      +      System.loadLibrary("cpp11_ref_qualifiers_typemaps");
      +    } catch (UnsatisfiedLinkError e) {
      +      System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
      +      System.exit(1);
      +    }
      +  }
      +
      +  public static void main(String argv[]) 
      +  {
      +    {
      +      TypemapsNamedParms tm = new TypemapsNamedParms();
      +      if (tm.fff(cpp11_ref_qualifiers_typemaps.FF1_MFP) != 2)
      +        throw new RuntimeException("failed");
      +      if (tm.ccc(cpp11_ref_qualifiers_typemaps.CC4_MFP) != 5)
      +        throw new RuntimeException("failed");
      +      if (tm.ggg(cpp11_ref_qualifiers_typemaps.GG7_MFP) != 8)
      +        throw new RuntimeException("failed");
      +      if (tm.hhh(cpp11_ref_qualifiers_typemaps.HH10_MFP) != 11)
      +        throw new RuntimeException("failed");
      +    }
      +    {
      +      TypemapsUnnamedParms tm = new TypemapsUnnamedParms();
      +      if (tm.fff(cpp11_ref_qualifiers_typemaps.FF1_MFP) != 3)
      +        throw new RuntimeException("failed");
      +      if (tm.ccc(cpp11_ref_qualifiers_typemaps.CC4_MFP) != 6)
      +        throw new RuntimeException("failed");
      +      if (tm.ggg(cpp11_ref_qualifiers_typemaps.GG7_MFP) != 9)
      +        throw new RuntimeException("failed");
      +      if (tm.hhh(cpp11_ref_qualifiers_typemaps.HH10_MFP) != 12)
      +        throw new RuntimeException("failed");
      +    }
      +  }
      +}
      +
      diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
      index 9cf6f00c6..2e92cd01b 100644
      --- a/Source/CParse/parser.y
      +++ b/Source/CParse/parser.y
      @@ -1895,7 +1895,7 @@ constant_directive :  CONSTANT identifier EQUAL definetype SEMI {
       		   $$ = 0;
       		 }
                      }
      -	       /* Member const function pointers . eg.
      +	       /* Member function pointers with qualifiers. eg.
       	         %constant short (Funcs::*pmf)(bool) const = &Funcs::F; */
       	       | CONSTANT type direct_declarator LPAREN parms RPAREN cv_ref_qualifier def_args SEMI {
       		 if (($8.type != T_ERROR) && ($8.type != T_SYMBOL)) {
      @@ -5116,7 +5116,7 @@ parameter_declarator : declarator def_args {
                     $$.id = 0;
       	      $$.defarg = $1.rawval ? $1.rawval : $1.val;
                   }
      -	    /* Member const function pointer parameters. eg.
      +	    /* Member function pointers with qualifiers. eg.
       	      int f(short (Funcs::*parm)(bool) const); */
       	    | direct_declarator LPAREN parms RPAREN cv_ref_qualifier {
       	      SwigType *t;
      @@ -5174,6 +5174,27 @@ plain_declarator : declarator {
       		$$.parms = 0;
       	      }
                   }
      +	    /* Member function pointers with qualifiers. eg.
      +	      int f(short (Funcs::*parm)(bool) const) */
      +	    | direct_declarator LPAREN parms RPAREN cv_ref_qualifier {
      +	      SwigType *t;
      +	      $$ = $1;
      +	      t = NewStringEmpty();
      +	      SwigType_add_function(t, $3);
      +	      if ($5.qualifier)
      +	        SwigType_push(t, $5.qualifier);
      +	      if (!$$.have_parms) {
      +		$$.parms = $3;
      +		$$.have_parms = 1;
      +	      }
      +	      if (!$$.type) {
      +		$$.type = t;
      +	      } else {
      +		SwigType_push(t, $$.type);
      +		Delete($$.type);
      +		$$.type = t;
      +	      }
      +	    }
                   | empty {
          	      $$.type = 0;
                     $$.id = 0;
      
      From f38e525a24fbaff57357c026824bc2c89ab98376 Mon Sep 17 00:00:00 2001
      From: William S Fulton 
      Date: Sun, 10 Sep 2017 12:49:24 +0100
      Subject: [PATCH 15/15] Warnings in testcases fix
      
      ---
       Examples/test-suite/cpp11_ref_qualifiers.i   | 2 ++
       Examples/test-suite/template_empty_inherit.i | 1 +
       2 files changed, 3 insertions(+)
      
      diff --git a/Examples/test-suite/cpp11_ref_qualifiers.i b/Examples/test-suite/cpp11_ref_qualifiers.i
      index 237234e9c..e37136770 100644
      --- a/Examples/test-suite/cpp11_ref_qualifiers.i
      +++ b/Examples/test-suite/cpp11_ref_qualifiers.i
      @@ -90,9 +90,11 @@ struct Renames {
       struct ConversionOperators {
         virtual operator string() & { return string(); }
         virtual operator string() && { return std::move(string()); }
      +  virtual ~ConversionOperators() {}
       };
       struct ConversionOperators2 {
         virtual operator string() && { return std::move(string()); }
      +  virtual ~ConversionOperators2() {}
       };
       %}
       
      diff --git a/Examples/test-suite/template_empty_inherit.i b/Examples/test-suite/template_empty_inherit.i
      index 308a01fda..5677b8b1a 100644
      --- a/Examples/test-suite/template_empty_inherit.i
      +++ b/Examples/test-suite/template_empty_inherit.i
      @@ -5,6 +5,7 @@
       %inline %{
       template struct Functor {
         virtual Result operator()(Arg x) const = 0;
      +  virtual ~Functor() {}
       };
       %}