From 15ebf3df03f5b57e46b7bc7a22aa58342ef0eb34 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sat, 7 May 2016 12:33:29 +0100 Subject: [PATCH] Fix assertion handling defaultargs Occurs when using %extend for a template class and the extended methods contain default arguments. Closes #611 --- CHANGES.current | 4 ++ Examples/test-suite/common.mk | 1 + ...ate_default_arg_overloaded_extend_runme.py | 20 +++++++++ .../template_default_arg_overloaded_extend.i | 44 +++++++++++++++++++ Source/CParse/parser.y | 25 ++++++++--- 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 Examples/test-suite/python/template_default_arg_overloaded_extend_runme.py create mode 100644 Examples/test-suite/template_default_arg_overloaded_extend.i diff --git a/CHANGES.current b/CHANGES.current index 1b29f0e4f..af6707824 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,10 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.9 (in progress) =========================== +2016-05-07: wsfulton + Fix #611. Fix assertion handling defaultargs when using %extend for a template + class and the extended methods contain default arguments. + 2016-05-05: ejulian [Python] Patch #617. Fix operator/ wrappers. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 9212a1c3e..ddcdc658b 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -402,6 +402,7 @@ CPP_TEST_CASES += \ template_default2 \ template_default_arg \ template_default_arg_overloaded \ + template_default_arg_overloaded_extend \ template_default_arg_virtual_destructor \ template_default_class_parms \ template_default_class_parms_typedef \ diff --git a/Examples/test-suite/python/template_default_arg_overloaded_extend_runme.py b/Examples/test-suite/python/template_default_arg_overloaded_extend_runme.py new file mode 100644 index 000000000..febc3dcf6 --- /dev/null +++ b/Examples/test-suite/python/template_default_arg_overloaded_extend_runme.py @@ -0,0 +1,20 @@ +from template_default_arg_overloaded_extend import * + +def check(flag): + if not flag: + raise RuntimeError("failed") + +rs = ResultSet() + +check(rs.go_get(0, SearchPoint()) == -1) +check(rs.go_get(0, SearchPoint(), 100) == 100) + +check(rs.go_get_template(0, SearchPoint()) == -2) +check(rs.go_get_template(0, SearchPoint(), 100) == 100) + +check(rs.over() == "over(int)") +check(rs.over(10) == "over(int)") +check(rs.over(SearchPoint()) == "over(giai2::SearchPoint, int)") +check(rs.over(SearchPoint(), 10) == "over(giai2::SearchPoint, int)") +check(rs.over(True, SearchPoint()) == "over(bool, gaia2::SearchPoint, int)") +check(rs.over(True, SearchPoint(), 10) == "over(bool, gaia2::SearchPoint, int)") diff --git a/Examples/test-suite/template_default_arg_overloaded_extend.i b/Examples/test-suite/template_default_arg_overloaded_extend.i new file mode 100644 index 000000000..1ccdc629a --- /dev/null +++ b/Examples/test-suite/template_default_arg_overloaded_extend.i @@ -0,0 +1,44 @@ +%module template_default_arg_overloaded_extend + +%inline %{ +namespace gaia2 { + +struct Filter {}; +struct SearchPoint {}; +struct DataSet {}; + +template +class BaseSearchSpace {}; + +template +class BaseResultSet { +public: + const char *over(int i = 0) { + return "over(int)"; + } +}; +} +%} + +// Specialized template extend +%extend gaia2::BaseResultSet { + int go_get(int n, gaia2::SearchPoint, int offset = -1) { + return offset; + } + const char *over(gaia2::SearchPoint, int x = 0) { + return "over(giai2::SearchPoint, int)"; + } +} + +// Generic extend for all template instantiations +%extend gaia2::BaseResultSet { + int go_get_template(int n, SearchPointType sss, int offset = -2) { + return offset; + } + const char *over(bool b, SearchPointType, int x = 0) { + return "over(bool, SearchPointType, int)"; + } +} + +%template(ResultSet) gaia2::BaseResultSet; + diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index b2e4f7122..51cd5b553 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -145,7 +145,7 @@ static Node *copy_node(Node *n) { Setattr(nn, key, k.item); continue; } - /* defaultargs will be patched back in later */ + /* defaultargs will be patched back in later in update_defaultargs() */ if (strcmp(ckey,"defaultargs") == 0) { Setattr(nn, "needs_defaultargs", "1"); continue; @@ -660,19 +660,26 @@ static void add_symbols_copy(Node *n) { } } +/* Add in the "defaultargs" attribute for functions in instantiated templates. + * n should be any instantiated template (class or start of linked list of functions). */ static void update_defaultargs(Node *n) { if (n) { Node *firstdefaultargs = n; update_defaultargs(firstChild(n)); n = nextSibling(n); + /* recursively loop through nodes of all types, but all we really need are the overloaded functions */ while (n) { update_defaultargs(firstChild(n)); - assert(!Getattr(n, "defaultargs")); - if (Getattr(n, "needs_defaultargs")) { - Setattr(n, "defaultargs", firstdefaultargs); - Delattr(n, "needs_defaultargs"); + if (!Getattr(n, "defaultargs")) { + if (Getattr(n, "needs_defaultargs")) { + Setattr(n, "defaultargs", firstdefaultargs); + Delattr(n, "needs_defaultargs"); + } else { + firstdefaultargs = n; + } } else { - firstdefaultargs = n; + /* Functions added in with %extend (for specialized template classes) will already have default args patched up */ + assert(Getattr(n, "defaultargs") == firstdefaultargs); } n = nextSibling(n); } @@ -2756,7 +2763,11 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Swig_symbol_setscope(csyms); } - /* Merge in %extend methods for this class */ + /* Merge in %extend methods for this class. + This only merges methods within %extend for a template specialized class such as + template class K {}; %extend K { ... } + The copy_node() call above has already added in the generic %extend methods such as + template class K {}; %extend K { ... } */ /* !!! This may be broken. We may have to add the %extend methods at the beginning of the class */