From b7332ce8ca101d314eddae0edbbf579f54370dc1 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Wed, 12 Jul 2023 13:35:06 +0100 Subject: [PATCH] Fix using declarations and templates with explicitly declared constructors Corner case problem fix for when the base template class was instantiated with %template including the default arguments and the base class had an explicitly declared constructor. Swig_symbol_template_deftype() was sometimes incorrectly finding a constructor instead of a template and thus failing to correctly expand the template default args. Problem noticed since 9cf049186bf5ba6c446c38cf30c9df9fc8b6c2cc where constructors are stored simply by their name instead of name plus template args. Probably fixes a few other subtle template problems when a template class contains default args. --- Examples/test-suite/common.mk | 1 + ...mplate_using_member_default_arg_runme.java | 22 +++++++++++++ ...template_using_member_default_arg_runme.py | 6 ++++ .../template_using_member_default_arg.i | 33 +++++++++++++++++++ Source/Swig/symbol.c | 15 +++++++-- 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 Examples/test-suite/java/template_using_member_default_arg_runme.java create mode 100644 Examples/test-suite/python/template_using_member_default_arg_runme.py create mode 100644 Examples/test-suite/template_using_member_default_arg.i diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 37ed70dd2..888464b5f 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -473,6 +473,7 @@ CPP_TEST_CASES += \ template_namespace_forward_declaration \ template_using_directive_and_declaration_forward \ template_using_directive_typedef \ + template_using_member_default_arg \ template_nested \ template_nested_flat \ template_nested_typemaps \ diff --git a/Examples/test-suite/java/template_using_member_default_arg_runme.java b/Examples/test-suite/java/template_using_member_default_arg_runme.java new file mode 100644 index 000000000..5939158ad --- /dev/null +++ b/Examples/test-suite/java/template_using_member_default_arg_runme.java @@ -0,0 +1,22 @@ +import template_using_member_default_arg.*; + +public class template_using_member_default_arg_runme { + + static { + try { + System.loadLibrary("template_using_member_default_arg"); + } 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[]) { + ThingADerivedInt a = new ThingADerivedInt(); + a.describeA(); + ThingBDerivedInt b = new ThingBDerivedInt(); + b.describeB(); + } +} + + diff --git a/Examples/test-suite/python/template_using_member_default_arg_runme.py b/Examples/test-suite/python/template_using_member_default_arg_runme.py new file mode 100644 index 000000000..432306a8a --- /dev/null +++ b/Examples/test-suite/python/template_using_member_default_arg_runme.py @@ -0,0 +1,6 @@ +from template_using_member_default_arg import * + +a = ThingADerivedInt() +a.describeA() +b = ThingBDerivedInt() +b.describeB() diff --git a/Examples/test-suite/template_using_member_default_arg.i b/Examples/test-suite/template_using_member_default_arg.i new file mode 100644 index 000000000..117abd0ee --- /dev/null +++ b/Examples/test-suite/template_using_member_default_arg.i @@ -0,0 +1,33 @@ +%module template_using_member_default_arg + +%inline %{ +template +struct ThingA { + ThingA() {} +protected: + void describeA() {} +}; +template +struct ThingB { + ThingB() {} +protected: + void describeB() {} +}; +%} + +%inline %{ +template +struct ThingADerived : ThingA { + using ThingA::describeA; +}; +template +struct ThingBDerived : ThingB { + using ThingB::describeB; +}; +%} + +%template(ThingAInt) ThingA; // was okay +%template(ThingADerivedInt) ThingADerived; + +%template(ThingBInt) ThingB; // was failing - using directive in this template was not found +%template(ThingBDerivedInt) ThingBDerived; diff --git a/Source/Swig/symbol.c b/Source/Swig/symbol.c index 8e24c9ec7..e44585f6f 100644 --- a/Source/Swig/symbol.c +++ b/Source/Swig/symbol.c @@ -553,6 +553,12 @@ void Swig_symbol_cadd(const_String_or_char_ptr name, Node *n) { String *cname = NewString(name); String *dname = Swig_symbol_template_deftype(cname, 0); if (!Equal(dname, name)) { + /* Add another symbol with all template default arguments expanded, eg + * + * template struct X {}; + * %template(XInt) X; + * + * then name=X, and dname=X so add X here too. */ Swig_symbol_cadd(dname, n); } Delete(dname); @@ -1589,6 +1595,10 @@ static int symbol_no_constructor(Node *n) { return !Checkattr(n, "nodeType", "constructor"); } +static int symbol_is_template(Node *n) { + return Checkattr(n, "nodeType", "template"); +} + /* ----------------------------------------------------------------------------- * Swig_symbol_type_qualify() * @@ -1944,6 +1954,7 @@ ParmList *Swig_symbol_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, * Swig_symbol_template_deftype() * * Apply default args to generic template type + * Return input type with template args expanded to include default template args * ----------------------------------------------------------------------------- */ #define SWIG_TEMPLATE_DEFTYPE_CACHE @@ -2018,9 +2029,9 @@ SwigType *Swig_symbol_template_deftype(const SwigType *type, Symtab *tscope) { String *targs = SwigType_templateargs(base); String *tsuffix = SwigType_templatesuffix(base); ParmList *tparms = SwigType_function_parms(targs, 0); - Node *tempn = Swig_symbol_clookup_local(tprefix, tscope); + Node *tempn = Swig_symbol_clookup_local_check(tprefix, tscope, symbol_is_template); if (!tempn && tsuffix && Len(tsuffix)) { - tempn = Swig_symbol_clookup(tprefix, 0); + tempn = Swig_symbol_clookup_check(tprefix, 0, symbol_is_template); } #ifdef SWIG_DEBUG Printf(stderr, "deftype type %s %s %d\n", e, tprefix, (long) tempn);