From 469f694ae6f0d0532b0e382dc82e8da7bff7c2ca Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Thu, 24 Mar 2022 20:52:58 +0000 Subject: [PATCH] Fix using declaration in derived class bugs Problem when all the base class's overloaded methods were overridden in the derived class - fixes "multiply defined" errors. Linked lists of the overloaded methods were not set up correctly when handling the using declaration. Closes #2244 --- CHANGES.current | 5 +++ Examples/test-suite/using_member_scopes.i | 54 +++++++++++++++++++++++ Source/Modules/typepass.cxx | 51 ++++++++++----------- 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 1de8dccab..dbb4ec9a7 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-03-24: wsfulton + #2244 Fix using declaration in derived class bugs when all the base + class's overloaded methods were overridden in the derived class - + fixes "multiply defined" errors. + 2022-03-23: wsfulton [Python] #1779 The -py3 option is deprecated and now has no effect on the code generated. Use of this option results in a deprecated warning. diff --git a/Examples/test-suite/using_member_scopes.i b/Examples/test-suite/using_member_scopes.i index 354988a0b..3245c9cc7 100644 --- a/Examples/test-suite/using_member_scopes.i +++ b/Examples/test-suite/using_member_scopes.i @@ -29,3 +29,57 @@ typedef not working yet */ } %} + + +%inline %{ +// Test using declaration in various positions before and after overloaded methods +// Testing where the derived class overrides all the base class methods (and more) +namespace Bites +{ + struct Base + { + virtual ~Base() {} + virtual void grab() {} + virtual void grab(int i) {} + }; + struct Derived1 : public Base + { + using Base::grab; + virtual void grab() {} + virtual void grab(int i) {} + }; + struct Derived2 : public Base + { + using Base::grab; + virtual void grab() {} + virtual void grab(int i) {} + virtual void grab(int i, double d) {} + }; + struct Derived3 : public Base + { + virtual void grab() {} + using Base::grab; + virtual void grab(int i) {} + }; + struct Derived4 : public Base + { + virtual void grab() {} + using Base::grab; + virtual void grab(int i) {} + virtual void grab(int i, double d) {} + }; + struct Derived5 : public Base + { + virtual void grab() {} + virtual void grab(int i) {} + using Base::grab; + }; + struct Derived6 : public Base + { + virtual void grab() {} + virtual void grab(int i) {} + virtual void grab(int i, double d) {} + using Base::grab; + }; +} +%} diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index e1c3753ce..6f01ec0e8 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -1159,14 +1159,30 @@ class TypePass:private Dispatcher { * which is hacked. */ if (Getattr(n, "sym:overloaded")) { int cnt = 0; + Node *ps = Getattr(n, "sym:previousSibling"); + Node *ns = Getattr(n, "sym:nextSibling"); + Node *fc = firstChild(n); + Node *firstoverloaded = Getattr(n, "sym:overloaded"); #ifdef DEBUG_OVERLOADED - Node *debugnode = n; - show_overloaded(n); + show_overloaded(firstoverloaded); #endif - if (!firstChild(n)) { + + if (firstoverloaded == n) { + // This 'using' node we are cutting out was the first node in the overloaded list. + // Change the first node in the list + Delattr(firstoverloaded, "sym:overloaded"); + firstoverloaded = fc ? fc : ns; + + // Correct all the sibling overloaded methods (before adding in new methods) + Node *nnn = ns; + while (nnn) { + Setattr(nnn, "sym:overloaded", firstoverloaded); + nnn = Getattr(nnn, "sym:nextSibling"); + } + } + + if (!fc) { // Remove from overloaded list ('using' node does not actually end up adding in any methods) - Node *ps = Getattr(n, "sym:previousSibling"); - Node *ns = Getattr(n, "sym:nextSibling"); if (ps) { Setattr(ps, "sym:nextSibling", ns); } @@ -1174,24 +1190,8 @@ class TypePass:private Dispatcher { Setattr(ns, "sym:previousSibling", ps); } } else { - // The 'using' node results in methods being added in - slot in the these methods here - Node *ps = Getattr(n, "sym:previousSibling"); - Node *ns = Getattr(n, "sym:nextSibling"); - Node *fc = firstChild(n); + // The 'using' node results in methods being added in - slot in these methods here Node *pp = fc; - - Node *firstoverloaded = Getattr(n, "sym:overloaded"); - if (firstoverloaded == n) { - // This 'using' node we are cutting out was the first node in the overloaded list. - // Change the first node in the list to its first sibling - Delattr(firstoverloaded, "sym:overloaded"); - Node *nnn = Getattr(firstoverloaded, "sym:nextSibling"); - firstoverloaded = fc; - while (nnn) { - Setattr(nnn, "sym:overloaded", firstoverloaded); - nnn = Getattr(nnn, "sym:nextSibling"); - } - } while (pp) { Node *ppn = Getattr(pp, "sym:nextSibling"); Setattr(pp, "sym:overloaded", firstoverloaded); @@ -1209,18 +1209,15 @@ class TypePass:private Dispatcher { Setattr(ns, "sym:previousSibling", pp); Setattr(pp, "sym:nextSibling", ns); } -#ifdef DEBUG_OVERLOADED - debugnode = firstoverloaded; -#endif } Delattr(n, "sym:previousSibling"); Delattr(n, "sym:nextSibling"); Delattr(n, "sym:overloaded"); Delattr(n, "sym:overname"); + clean_overloaded(firstoverloaded); #ifdef DEBUG_OVERLOADED - show_overloaded(debugnode); + show_overloaded(firstoverloaded); #endif - clean_overloaded(n); // Needed? } Delete(n_decl_list); }