diff --git a/CHANGES.current b/CHANGES.current index 90edd76f3..bd468adc8 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,3 +1,13 @@ Version 1.3.34 (in progress) ============================ +11/30/2007: wsfulton + Fix using statements using a base class method where the methods were overloaded. + Depending on the order of the using statements and method declarations, these + were previously generating uncompileable wrappers, eg: + + struct Derived : Base { + virtual void funk(); + using Base::funk; + }; + diff --git a/Examples/test-suite/python/using_composition_runme.py b/Examples/test-suite/python/using_composition_runme.py index 866453a2a..6baa16d13 100644 --- a/Examples/test-suite/python/using_composition_runme.py +++ b/Examples/test-suite/python/using_composition_runme.py @@ -2,10 +2,33 @@ from using_composition import * f = FooBar() if f.blah(3) != 3: - raise RuntimeError,"blah(int)" + raise RuntimeError,"FooBar::blah(int)" if f.blah(3.5) != 3.5: - raise RuntimeError,"blah(double)" + raise RuntimeError,"FooBar::blah(double)" if f.blah("hello") != "hello": - raise RuntimeError,"blah(char *)" + raise RuntimeError,"FooBar::blah(char *)" + + +f = FooBar2() +if f.blah(3) != 3: + raise RuntimeError,"FooBar2::blah(int)" + +if f.blah(3.5) != 3.5: + raise RuntimeError,"FooBar2::blah(double)" + +if f.blah("hello") != "hello": + raise RuntimeError,"FooBar2::blah(char *)" + + +f = FooBar3() +if f.blah(3) != 3: + raise RuntimeError,"FooBar3::blah(int)" + +if f.blah(3.5) != 3.5: + raise RuntimeError,"FooBar3::blah(double)" + +if f.blah("hello") != "hello": + raise RuntimeError,"FooBar3::blah(char *)" + diff --git a/Examples/test-suite/python/using_inherit_runme.py b/Examples/test-suite/python/using_inherit_runme.py index 15fee6698..b00e66ec3 100644 --- a/Examples/test-suite/python/using_inherit_runme.py +++ b/Examples/test-suite/python/using_inherit_runme.py @@ -2,7 +2,48 @@ from using_inherit import * b = Bar() if b.test(3) != 3: - raise RuntimeError,"test(int)" + raise RuntimeError,"Bar::test(int)" if b.test(3.5) != 3.5: - raise RuntimeError, "test(double)" + raise RuntimeError, "Bar::test(double)" + + +b = Bar2() +if b.test(3) != 6: + raise RuntimeError,"Bar2::test(int)" + +if b.test(3.5) != 7.0: + raise RuntimeError, "Bar2::test(double)" + + +b = Bar3() +if b.test(3) != 6: + raise RuntimeError,"Bar3::test(int)" + +if b.test(3.5) != 7.0: + raise RuntimeError, "Bar3::test(double)" + + +b = Bar4() +if b.test(3) != 6: + raise RuntimeError,"Bar4::test(int)" + +if b.test(3.5) != 7.0: + raise RuntimeError, "Bar4::test(double)" + + +b = Fred1() +if b.test(3) != 3: + raise RuntimeError,"Fred1::test(int)" + +if b.test(3.5) != 7.0: + raise RuntimeError, "Fred1::test(double)" + + +b = Fred2() +if b.test(3) != 3: + raise RuntimeError,"Fred2::test(int)" + +if b.test(3.5) != 7.0: + raise RuntimeError, "Fred2::test(double)" + diff --git a/Examples/test-suite/ruby/using_composition_runme.rb b/Examples/test-suite/ruby/using_composition_runme.rb index 8d33deb88..b9500cb27 100644 --- a/Examples/test-suite/ruby/using_composition_runme.rb +++ b/Examples/test-suite/ruby/using_composition_runme.rb @@ -15,14 +15,42 @@ include Using_composition f = FooBar.new if f.blah(3) != 3 - raise RuntimeError,"blah(int)" + raise RuntimeError,"FooBar::blah(int)" end if f.blah(3.5) != 3.5 - raise RuntimeError,"blah(double)" + raise RuntimeError,"FooBar::blah(double)" end if f.blah("hello") != "hello" - raise RuntimeError,"blah(char *)" + raise RuntimeError,"FooBar::blah(char *)" +end + + +f = FooBar2.new +if f.blah(3) != 3 + raise RuntimeError,"FooBar2::blah(int)" +end + +if f.blah(3.5) != 3.5 + raise RuntimeError,"FooBar2::blah(double)" +end + +if f.blah("hello") != "hello" + raise RuntimeError,"FooBar2::blah(char *)" +end + + +f = FooBar3.new +if f.blah(3) != 3 + raise RuntimeError,"FooBar3::blah(int)" +end + +if f.blah(3.5) != 3.5 + raise RuntimeError,"FooBar3::blah(double)" +end + +if f.blah("hello") != "hello" + raise RuntimeError,"FooBar3::blah(char *)" end diff --git a/Examples/test-suite/ruby/using_inherit_runme.rb b/Examples/test-suite/ruby/using_inherit_runme.rb index 72c0a5ae3..1b7e4043a 100644 --- a/Examples/test-suite/ruby/using_inherit_runme.rb +++ b/Examples/test-suite/ruby/using_inherit_runme.rb @@ -15,10 +15,60 @@ include Using_inherit b = Bar.new if b.test(3) != 3 - raise RuntimeError,"test(int)" + raise RuntimeError,"Bar::test(int)" end if b.test(3.5) != 3.5 - raise RuntimeError, "test(double)" + raise RuntimeError, "Bar::test(double)" end +b = Bar2.new +if b.test(3) != 6 + raise RuntimeError,"Bar2::test(int)" +end + +if b.test(3.5) != 7.0 + raise RuntimeError, "Bar2::test(double)" +end + + +b = Bar3.new +if b.test(3) != 6 + raise RuntimeError,"Bar3::test(int)" +end + +if b.test(3.5) != 7.0 + raise RuntimeError, "Bar3::test(double)" +end + + +b = Bar4.new +if b.test(3) != 6 + raise RuntimeError,"Bar4::test(int)" +end + +if b.test(3.5) != 7.0 + raise RuntimeError, "Bar4::test(double)" +end + + +b = Fred1.new +if b.test(3) != 3 + raise RuntimeError,"Fred1::test(int)" +end + +if b.test(3.5) != 7.0 + raise RuntimeError, "Fred1::test(double)" +end + + +b = Fred2.new +if b.test(3) != 3 + raise RuntimeError,"Fred2::test(int)" +end + +if b.test(3.5) != 7.0 + raise RuntimeError, "Fred2::test(double)" +end + + diff --git a/Examples/test-suite/using_composition.i b/Examples/test-suite/using_composition.i index cc5750269..f1fd1ff37 100644 --- a/Examples/test-suite/using_composition.i +++ b/Examples/test-suite/using_composition.i @@ -26,4 +26,18 @@ public: char *blah(char *x) { return x; } }; +class FooBar2 : public Foo, public Bar { +public: + char *blah(char *x) { return x; } + using Foo::blah; + using Bar::blah; +}; + +class FooBar3 : public Foo, public Bar { +public: + using Foo::blah; + char *blah(char *x) { return x; } + using Bar::blah; +}; + %} diff --git a/Examples/test-suite/using_inherit.i b/Examples/test-suite/using_inherit.i index 4c3a694b0..b4fe9664a 100644 --- a/Examples/test-suite/using_inherit.i +++ b/Examples/test-suite/using_inherit.i @@ -17,5 +17,38 @@ public: using Foo::test; }; +class Bar2 : public Foo { +public: + int test(int x) { return x*2; } + double test(double x) { return x*2; }; + using Foo::test; +}; + +class Bar3 : public Foo { +public: + int test(int x) { return x*2; } + double test(double x) { return x*2; }; + using Foo::test; +}; + +class Bar4 : public Foo { +public: + int test(int x) { return x*2; } + using Foo::test; + double test(double x) { return x*2; }; +}; + +class Fred1 : public Foo { +public: + using Foo::test; + double test(double x) { return x*2; }; +}; + +class Fred2 : public Foo { +public: + double test(double x) { return x*2; }; + using Foo::test; +}; + %} diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index d72dd803e..b7e21ad26 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -564,7 +564,6 @@ class TypePass:private Dispatcher { * ------------------------------------------------------------ */ virtual int cDeclaration(Node *n) { - if (NoExcept) { Delattr(n, "throws"); } @@ -777,6 +776,35 @@ class TypePass:private Dispatcher { return enumDeclaration(n); } +#ifdef DEBUG_OVERLOADED + static void show_overloaded(Node *n) { + Node *c = Getattr(n, "sym:overloaded"); + Node *checkoverloaded = c; + Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c); + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + if (Getattr(c, "sym:overloaded") != checkoverloaded) { + Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded); + Swig_print_node(c); + exit (1); + } + + String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl"); + Printf(stdout, " show_overloaded %s::%s(%s) [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c)); + if (!Getattr(c, "sym:overloaded")) { + Printf(stdout, "sym:overloaded error.....%p\n", c); + Swig_print_node(c); + exit (1); + } + c = Getattr(c, "sym:nextSibling"); + } + Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name")); + } +#endif + /* ------------------------------------------------------------ * usingDeclaration() * ------------------------------------------------------------ */ @@ -816,10 +844,8 @@ class TypePass:private Dispatcher { Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname"))); } } else { - /* Only a single symbol is being used. There are only a few symbols that we actually care about. These are typedef, class declarations, and enum */ - String *ntype = nodeType(ns); if (Strcmp(ntype, "cdecl") == 0) { if (checkAttribute(ns, "storage", "typedef")) { @@ -841,9 +867,15 @@ class TypePass:private Dispatcher { || (Getattr(c, "feature:extend") && !Getattr(c, "code")) || GetFlag(c, "feature:ignore"))) { + /* Don't generate a method if the method is overridden in this class, + * for example don't generate another m(bool) should there be a Base::m(bool) : + * struct Derived : Base { + * void m(bool); + * using Base::m; + * }; + */ String *csymname = Getattr(c, "sym:name"); if (!csymname || (Strcmp(csymname, symname) == 0)) { - /* Check for existence in overload list already */ { String *decl = Getattr(c, "decl"); Node *over = Getattr(n, "sym:overloaded"); @@ -918,6 +950,75 @@ class TypePass:private Dispatcher { } } } + + /* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the + * list of overloaded methods we have just added in as child nodes to the "using" node. + * The node will still exist, it is just the symbol table linked list of overloaded methods + * which is hacked. */ + if (Getattr(n, "sym:overloaded")) + { +#ifdef DEBUG_OVERLOADED +show_overloaded(n); +#endif + int cnt = 0; + Node *debugnode = n; + if (!firstChild(n)) { + // 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); + } + if (ns) { + 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); + 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); + Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++)); + if (ppn) + pp = ppn; + else + break; + } + if (ps) { + Setattr(ps, "sym:nextSibling", fc); + Setattr(fc, "sym:previousSibling", ps); + } + if (ns) { + Setattr(ns, "sym:previousSibling", pp); + Setattr(pp, "sym:nextSibling", ns); + } + debugnode = firstoverloaded; + } + Delattr(n, "sym:previousSibling"); + Delattr(n, "sym:nextSibling"); + Delattr(n, "sym:overloaded"); + Delattr(n, "sym:overname"); +#ifdef DEBUG_OVERLOADED +show_overloaded(debugnode); +#endif + clean_overloaded(n); // Needed? + } } } } else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) { diff --git a/Source/Modules/utils.cxx b/Source/Modules/utils.cxx index 1eb4adec3..8a89be5f2 100644 --- a/Source/Modules/utils.cxx +++ b/Source/Modules/utils.cxx @@ -46,19 +46,17 @@ int is_member_director(Node *member) { return is_member_director(Getattr(member, "parentNode"), member); } - /* Clean overloaded list. Removes templates, ignored, and errors */ void clean_overloaded(Node *n) { Node *nn = Getattr(n, "sym:overloaded"); Node *first = 0; - int cnt = 0; while (nn) { String *ntype = nodeType(nn); if ((GetFlag(nn, "feature:ignore")) || (Getattr(nn, "error")) || (Strcmp(ntype, "template") == 0) || - ((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn)) || ((Strcmp(ntype, "using") == 0) && !firstChild(nn))) { + ((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn))) { /* Remove from overloaded list */ Node *ps = Getattr(nn, "sym:previousSibling"); Node *ns = Getattr(nn, "sym:nextSibling"); @@ -73,40 +71,6 @@ void clean_overloaded(Node *n) { Delattr(nn, "sym:overloaded"); nn = ns; continue; - } else if ((Strcmp(ntype, "using") == 0)) { - /* A possibly dangerous parse tree hack. We're going to - cut the parse tree node out and stick in the resolved - using declarations */ - - Node *ps = Getattr(nn, "sym:previousSibling"); - Node *ns = Getattr(nn, "sym:nextSibling"); - Node *un = firstChild(nn); - Node *pn = un; - - if (!first) { - first = un; - } - while (pn) { - Node *ppn = Getattr(pn, "sym:nextSibling"); - Setattr(pn, "sym:overloaded", first); - Setattr(pn, "sym:overname", NewStringf("%s_%d", Getattr(nn, "sym:overname"), cnt++)); - if (ppn) - pn = ppn; - else - break; - } - if (ps) { - Setattr(ps, "sym:nextSibling", un); - Setattr(un, "sym:previousSibling", ps); - } - if (ns) { - Setattr(ns, "sym:previousSibling", pn); - Setattr(pn, "sym:nextSibling", ns); - } - if (!first) { - first = un; - Setattr(nn, "sym:overloaded", first); - } } else { if (!first) first = nn; @@ -115,6 +79,7 @@ void clean_overloaded(Node *n) { nn = Getattr(nn, "sym:nextSibling"); } if (!first || (first && !Getattr(first, "sym:nextSibling"))) { - Delattr(n, "sym:overloaded"); + if (Getattr(n, "sym:overloaded")) + Delattr(n, "sym:overloaded"); } }