From 4729cf2b1f44e57f46d13758009b10cec5af47b6 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 18 Nov 2022 18:49:48 +0000 Subject: [PATCH] Duplicate class template instantiations via %template changes Named duplicate class template instantiations now issue a warning and are ignored. Duplicate empty class template instantiations are quietly ignored. The test cases are fixed for this new behaviour. This commit is a pre-requisite for the near future so that the Python builtin wrappers can correctly use the SwigType_namestr function without generating duplicate symbol names. --- CHANGES.current | 44 ++++++ Doc/Manual/Contents.html | 1 + Doc/Manual/SWIGPlus.html | 139 ++++++++++++++---- Doc/Manual/Warnings.html | 1 + .../errors/cpp_template_class_repeat.i | 34 +++++ .../errors/cpp_template_class_repeat.stderr | 6 + .../cpp_template_duplicate_names.stderr | 12 +- .../test-suite/errors/cpp_template_repeat.i | 13 +- .../errors/cpp_template_repeat.stderr | 6 + .../test-suite/template_class_reuse_name.i | 3 + Examples/test-suite/template_default2.i | 14 +- .../template_specialization_defarg.i | 2 + Source/CParse/cparse.h | 2 +- Source/CParse/parser.y | 15 +- Source/CParse/templ.c | 45 +++++- Source/Modules/typepass.cxx | 1 + 16 files changed, 283 insertions(+), 55 deletions(-) create mode 100644 Examples/test-suite/errors/cpp_template_class_repeat.i create mode 100644 Examples/test-suite/errors/cpp_template_class_repeat.stderr diff --git a/CHANGES.current b/CHANGES.current index 3cc2c6066..e184cc6d8 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,50 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.2.0 (in progress) =========================== +2022-11-18: wsfulton + Duplicate class template instantiations via %template now issue a warning and are ignored. + + %template(Aint) A; + %template(Aint2) A; // Now ignored and issues a warning + + example.i:7: Warning 404: Duplicate template instantiation of 'A< int >' with name 'Aint2' ignored, + example.i:6: Warning 404: previous instantiation of 'A< int >' with name 'Aint'. + + A single empty template instantiation before a named instantiation is the one exception + for allowing duplicate template instantiations as the empty template instantation does not + create a wrapper for the template, it merely adds the instantiation into SWIG's internal + type system. + Duplicate empty template instantiations are quietly ignored. + + %template() B; + %template(Bint) B; // OK + + %template() C; + %template() C; // Quietly ignored now + %template(Cint) C; // OK + + Note that default template parameters are considered when looking for duplicates such as: + + template struct D {}; + %template(Dint) D; + %template(Dintshort) D; + + example.i:7: Warning 404: Duplicate template instantiation of 'D< int,short >' with name 'Dintshort' ignored, + example.i:6: Warning 404: previous instantiation of 'D< int >' with name 'Dint'. + + Note that the following always was ignored, but that was because the chosen name was a + duplicate rather than the template being a duplicate: + + %template(Eint) E; + %template(Eint) E; // Always has been ignored as a redefined identifier + + The old warning was: + + example.i:7: Warning 302: Identifier 'Eint' redefined (ignored) (Renamed from 'E< int >'), + example.i:6: Warning 302: previous definition of 'Eint' (Renamed from 'E< int >'). + + *** POTENTIAL INCOMPATIBILITY *** + 2022-11-05: wsfulton #2417 Fix -swiglib for Windows when building with CMake. diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index fd74ab299..cecd54958 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -260,6 +260,7 @@
  • Function templates
  • Default template arguments
  • Template base classes +
  • Empty template instantiation
  • Template specialization
  • Member templates
  • Scoping and templates diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index b4b9acb17..cc33d6152 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -57,6 +57,7 @@
  • Function templates
  • Default template arguments
  • Template base classes +
  • Empty template instantiation
  • Template specialization
  • Member templates
  • Scoping and templates @@ -3261,10 +3262,28 @@ void foo(List<Integer> *x); In this case, List<Integer> is exactly the same type as List<int>. Any use of List<Integer> is mapped back to the instantiation of List<int> created earlier. Therefore, it is -not necessary to instantiate a new class for the type Integer (doing so is -redundant and will simply result in code bloat). +not correct to instantiate a new class for the type Integer. +An attempt to do so such as:

    +
    +
    +%template(intList) List<int>;
    +%template(IntegerList) List<Integer>;   // Ignored
    +
    +
    + +

    +will result in the duplicate instantiation being ignored with a warning: +

    + +
    +
    +example.i:48: Warning 404: Duplicate template instantiation of 'List< Integer >' with name 'IntegerList' ignored,
    +example.i:47: Warning 404: previous instantiation of 'List< int >' with name 'intList'.
    +
    +
    +

    The template provided to %template for instantiation must be the actual template and not a typedef to a template.

    @@ -3333,36 +3352,49 @@ original template definition. Template default arguments are supported. For ex
    -template vector<typename T, int max=100> class vector {
    +template <typename T, int max=100> class vector {
     ...
     };
     
    -%template(intvec) vector<int>;           // OK
    +%template(intvec) vector<int>;            // OK
     %template(vec1000) vector<int, 1000>;     // OK
     

    The %template directive should not be used to wrap the same -template instantiation more than once in the same scope. This will -generate an error. For example: +template instantiation more than once. This also applies to default parameters +where a template parameter specified in the instantiation is the same as the default parameter. +For example:

    -%template(intList) List<int>;
    -%template(Listint) List<int>;    // Error.   Template already wrapped.
    +%template(vec) vector<double>;            // OK
    +%template(vec100) vector<double, 100>;    // Ignored
     

    -This error is caused because the template expansion results in two -identical classes with the same name. This generates a symbol table -conflict. Besides, it probably more efficient to only wrap a specific -instantiation only once in order to reduce the potential for code -bloat. +will warn:

    +
    +
    +example.i:59: Warning 404: Duplicate template instantiation of 'vector< double,100 >' with name 'vec100' ignored,
    +example.i:58: Warning 404: previous instantiation of 'vector< double >' with name 'vec'.
    +
    +
    + +

    +If this was not ignored, the template expansion would result in two identical classes. +An identical instantiation is only wrapped once in order to reduce code bloat. +

    + +

    +Compatibility Note: Versions prior to SWIG-4.2.0 would sometimes not detect and prevent duplicate +instantiations, such as when the wrapped name was different. +

    6.18.4 Template base classes

    @@ -3429,20 +3461,6 @@ code (and base classes need to be wrapped before derived classes). Don't worry--if you get the order wrong, SWIG should generate a warning message.

    -

    -Occasionally, you may need to tell SWIG about base classes that are defined by templates, -but which aren't supposed to be wrapped. Since SWIG is not able to automatically -instantiate templates for this purpose, you must do it manually. To do this, simply -use the empty template instantiation, that is, %template with no name. For example: -

    - -
    -
    -// Instantiate traits<double, double>, but don't wrap it.
    -%template() traits<double, double>;
    -
    -
    -

    If you have to instantiate a lot of different classes for many different types, you might consider writing a SWIG macro. For example: @@ -3468,7 +3486,66 @@ TEMPLATE_WRAP(PairStringInt, std::pair<string, int>) Note the use of a vararg macro for the type T. If this wasn't used, the comma in the templated type in the last example would not be possible.

    -

    6.18.5 Template specialization

    +

    6.18.5 Empty template instantiation

    + + +

    +Occasionally, you may need to tell SWIG about classes that are defined by templates, +but which aren't supposed to be wrapped. Since SWIG is not able to automatically +instantiate templates for this purpose, you must do it manually. To do this, simply +use %template(), that is the empty template instantiation that omits providing a name. For example: +

    + +
    +
    +template<typename T> struct Traits {
    +  typedef T type;
    +};
    +%}
    +
    +%template() Traits<int>; // instantiate Traits<int>, but don't wrap it
    +
    +void traitor(Traits<int>::type val);
    +
    +
    + +

    +Without a template instantiation, SWIG does not know that the first parameter to the traitor +function is type int and passing an integer to this function from any target language won't work. +The empty template instantiation adds the appropriate type information into SWIG's type system, without +forcing one to wrap the Traits class. +

    + +

    +Duplicate template instantiation are not allowed, as described in the +Default template arguments section above. +There is one exception where a named template instantiation can be followed by an empty template instantiation. +Duplicate empty template instantiations are silently ignored, unlike duplicate named template instantiations. +

    + +

    +Unlike template class instantiations, template function instantiations must have a name. +Consider the following: +

    + +
    +
    +template<class T> T tfunc(T x) { };
    +%template() tfunc<double>;
    +
    +
    + +

    +The empty template instantiation will be ignored with: +

    + +
    +
    +example.i:9: Warning 519: %template() contains no name. Template method ignored: tfunc< double >(double)
    +
    +
    + +

    6.18.6 Template specialization

    @@ -3558,7 +3635,7 @@ SWIG implements template argument deduction so that the following partial specia -

    6.18.6 Member templates

    +

    6.18.7 Member templates

    @@ -3770,7 +3847,7 @@ constructor, that will dispatch the proper call depending on the argument type.

    -

    6.18.7 Scoping and templates

    +

    6.18.8 Scoping and templates

    @@ -3871,7 +3948,7 @@ template class C<int>;

    -

    6.18.8 More on templates

    +

    6.18.9 More on templates

    diff --git a/Doc/Manual/Warnings.html b/Doc/Manual/Warnings.html index b20b69cef..9d5361dae 100644 --- a/Doc/Manual/Warnings.html +++ b/Doc/Manual/Warnings.html @@ -493,6 +493,7 @@ example.i(4) : Syntax error in input(1).

  • 401. Nothing known about class 'name'. Ignored.
  • 402. Base class 'name' is incomplete.
  • 403. Class 'name' might be abstract. +
  • 404. Duplicate template instantiation of 'type' with name 'name' ignored, previous instantiation of 'type' with name 'name'.
  • 450. Reserved
  • 451. Setting const char * variable may leak memory.
  • 452. Reserved diff --git a/Examples/test-suite/errors/cpp_template_class_repeat.i b/Examples/test-suite/errors/cpp_template_class_repeat.i new file mode 100644 index 000000000..c8bffd47a --- /dev/null +++ b/Examples/test-suite/errors/cpp_template_class_repeat.i @@ -0,0 +1,34 @@ +%module xxx + +template struct A {}; +%template(Aint) A; +%template(Aint2) A; // Now ignored and issues a warning + +template struct B {}; +%template() B; +%template(Bint) B; // OK + +template struct C {}; +%template() C; +%template() C; // Quietly ignored now +%template(Cint) C; // OK + +template struct D {}; +%template(Dint) D; +%template(Dintshort) D; + +template struct E {}; +%template(Eint) E; +%template(Eint) E; // Always has been ignored as a redefined identifier + + +template struct F {}; +%template(Fint) F; +%template() F; // Quietly ignored +%template() F; // Quietly ignored + +template struct G {}; +%template() G; +%template() G; // Quietly ignored +%template(Gint) G; +%template() G; // Quietly ignored diff --git a/Examples/test-suite/errors/cpp_template_class_repeat.stderr b/Examples/test-suite/errors/cpp_template_class_repeat.stderr new file mode 100644 index 000000000..db283dc26 --- /dev/null +++ b/Examples/test-suite/errors/cpp_template_class_repeat.stderr @@ -0,0 +1,6 @@ +cpp_template_class_repeat.i:5: Warning 404: Duplicate template instantiation of 'A< int >' with name 'Aint2' ignored, +cpp_template_class_repeat.i:4: Warning 404: previous instantiation of 'A< int >' with name 'Aint'. +cpp_template_class_repeat.i:18: Warning 404: Duplicate template instantiation of 'D< int,short >' with name 'Dintshort' ignored, +cpp_template_class_repeat.i:17: Warning 404: previous instantiation of 'D< int >' with name 'Dint'. +cpp_template_class_repeat.i:22: Warning 404: Duplicate template instantiation of 'E< int >' with name 'Eint' ignored, +cpp_template_class_repeat.i:21: Warning 404: previous instantiation of 'E< int >' with name 'Eint'. diff --git a/Examples/test-suite/errors/cpp_template_duplicate_names.stderr b/Examples/test-suite/errors/cpp_template_duplicate_names.stderr index 9856ff563..9e70963a8 100644 --- a/Examples/test-suite/errors/cpp_template_duplicate_names.stderr +++ b/Examples/test-suite/errors/cpp_template_duplicate_names.stderr @@ -2,13 +2,13 @@ cpp_template_duplicate_names.i:14: Warning 302: Identifier 'Duplicate1' redefine cpp_template_duplicate_names.i:13: Warning 302: previous definition of 'Duplicate1'. cpp_template_duplicate_names.i:14: Warning 302: Identifier 'Duplicate1' redefined (ignored), cpp_template_duplicate_names.i:13: Warning 302: previous definition of 'Duplicate1'. -cpp_template_duplicate_names.i:25: Warning 302: Identifier 'Duplicate2_0' redefined (ignored) (Renamed from 'Duplicate2< 0 >'), -cpp_template_duplicate_names.i:24: Warning 302: previous definition of 'Duplicate2_0' (Renamed from 'Duplicate2< 0 >'). -cpp_template_duplicate_names.i:35: Warning 302: Identifier 'Duplicate3' redefined (ignored) (Renamed from 'Duplicate3< 0 >'), -cpp_template_duplicate_names.i:31: Warning 302: previous definition of 'Duplicate3'. +cpp_template_duplicate_names.i:25: Warning 404: Duplicate template instantiation of 'Duplicate2< 0 >' with name 'Duplicate2_0' ignored, +cpp_template_duplicate_names.i:24: Warning 404: previous instantiation of 'Duplicate2< 0 >' with name 'Duplicate2_0'. +cpp_template_duplicate_names.i:35: Warning 404: Duplicate template instantiation of 'Duplicate3< 0 >' with name 'Duplicate3' ignored, +cpp_template_duplicate_names.i:34: Warning 404: previous instantiation of 'Duplicate3< 0 >' with name 'Duplicate3'. cpp_template_duplicate_names.i:47: Warning 302: Identifier 'Duplicate4' redefined (ignored), cpp_template_duplicate_names.i:46: Warning 302: previous definition of 'Duplicate4'. cpp_template_duplicate_names.i:47: Warning 302: Identifier 'Duplicate4' redefined (ignored), cpp_template_duplicate_names.i:46: Warning 302: previous definition of 'Duplicate4'. -cpp_template_duplicate_names.i:50: Warning 302: Identifier 'Duplicate4' redefined (ignored) (Renamed from 'Duplicate4< 0 >'), -cpp_template_duplicate_names.i:46: Warning 302: previous definition of 'Duplicate4'. +cpp_template_duplicate_names.i:50: Warning 404: Duplicate template instantiation of 'Duplicate4< 0 >' with name 'Duplicate4' ignored, +cpp_template_duplicate_names.i:49: Warning 404: previous instantiation of 'Duplicate4< 0 >' with name 'Duplicate4'. diff --git a/Examples/test-suite/errors/cpp_template_repeat.i b/Examples/test-suite/errors/cpp_template_repeat.i index f170080b7..08d378223 100644 --- a/Examples/test-suite/errors/cpp_template_repeat.i +++ b/Examples/test-suite/errors/cpp_template_repeat.i @@ -4,4 +4,15 @@ template T blah(T x) { }; %template(iblah) blah; %template(iiblah) blah; -// The second %template instantiation above should surely be ignored with a warning, but doesn't atm + +// empty template instantiations for template functions warn (unlike for template classes) +%template() blah; +%template() blah; +%template() blah; + +%template(sblah) blah; +%template(sblah) blah; + +%template() blah; +%template() blah; +%template(sblah) blah; diff --git a/Examples/test-suite/errors/cpp_template_repeat.stderr b/Examples/test-suite/errors/cpp_template_repeat.stderr index e69de29bb..7ab04f2a3 100644 --- a/Examples/test-suite/errors/cpp_template_repeat.stderr +++ b/Examples/test-suite/errors/cpp_template_repeat.stderr @@ -0,0 +1,6 @@ +cpp_template_repeat.i:6: Warning 404: Duplicate template instantiation of 'blah< int >' with name 'iiblah' ignored, +cpp_template_repeat.i:5: Warning 404: previous instantiation of 'blah< int >' with name 'iblah'. +cpp_template_repeat.i:14: Warning 404: Duplicate template instantiation of 'blah< short >' with name 'sblah' ignored, +cpp_template_repeat.i:13: Warning 404: previous instantiation of 'blah< short >' with name 'sblah'. +cpp_template_repeat.i:9: Warning 519: %template() contains no name. Template method ignored: blah< double >(double) +cpp_template_repeat.i:16: Warning 519: %template() contains no name. Template method ignored: blah< char const * >(char const *) diff --git a/Examples/test-suite/template_class_reuse_name.i b/Examples/test-suite/template_class_reuse_name.i index 818816d0e..03c5c8d1f 100644 --- a/Examples/test-suite/template_class_reuse_name.i +++ b/Examples/test-suite/template_class_reuse_name.i @@ -97,6 +97,7 @@ namespace Space { %warnfilter(SWIGWARN_PARSE_REDEFINED) Space::Duplicate2; +%warnfilter(SWIGWARN_TYPE_REDEFINED) Space::Duplicate2; %inline %{ namespace Space { template struct Duplicate2 { void n(){}; }; @@ -107,6 +108,7 @@ namespace Space { %warnfilter(SWIGWARN_PARSE_REDEFINED) Space::Duplicate3; +%warnfilter(SWIGWARN_TYPE_REDEFINED) Space::Duplicate3; %inline %{ namespace Space { template struct Duplicate3 { void n(){}; }; @@ -123,6 +125,7 @@ namespace Space { %} %warnfilter(SWIGWARN_PARSE_REDEFINED) Space::Duplicate4; +%warnfilter(SWIGWARN_TYPE_REDEFINED) Space::Duplicate4<0>; namespace Space { template struct Duplicate4 { void ff(){}; }; template struct Duplicate4 { void ff(){}; }; diff --git a/Examples/test-suite/template_default2.i b/Examples/test-suite/template_default2.i index 9ba0455f1..1a22410d2 100644 --- a/Examples/test-suite/template_default2.i +++ b/Examples/test-suite/template_default2.i @@ -17,6 +17,16 @@ static const Polarization pmode = UnaryPolarization; }; + struct traits2 + { + static const Polarization pmode = UnaryPolarization; + }; + + struct traits3 + { + static const Polarization pmode = UnaryPolarization; + }; + template > // **** problem here ***** @@ -37,8 +47,8 @@ namespace oss Interface_tpl >; // These don't - %template(Module_UP2) Module; - %template(Module_UP3) Module; + %template(Module_UP2) Module; + %template(Module_UP3) Module; } diff --git a/Examples/test-suite/template_specialization_defarg.i b/Examples/test-suite/template_specialization_defarg.i index 2f664c6f2..1216ab09c 100644 --- a/Examples/test-suite/template_specialization_defarg.i +++ b/Examples/test-suite/template_specialization_defarg.i @@ -1,5 +1,7 @@ %module template_specialization_defarg +%warnfilter(SWIGWARN_TYPE_REDEFINED) C; // note that warning is actually for the equivalent C diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h index 2b63f034d..42ce87cef 100644 --- a/Source/CParse/cparse.h +++ b/Source/CParse/cparse.h @@ -66,7 +66,7 @@ extern "C" { /* templ.c */ extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope); - extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, Symtab *tscope); + extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, String *symname, Symtab *tscope); extern void Swig_cparse_debug_templates(int); #ifdef __cplusplus diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 7f685e84e..61fac2b2e 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -2822,6 +2822,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Symtab *tscope = 0; int specialized = 0; int variadic = 0; + String *symname = $3 ? NewString($3) : 0; $$ = 0; @@ -2841,7 +2842,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va This is closer to the C++ (typedef) behavior. */ - n = Swig_cparse_template_locate($5,$7,tscope); + n = Swig_cparse_template_locate($5, $7, symname, tscope); /* Patch the argument types to respect namespaces */ p = $7; @@ -2966,7 +2967,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Setattr(templnode,"sym:typename","1"); } /* for now, nested %template is allowed only in the same scope as the template declaration */ - if ($3 && !(nnisclass && ((outer_class && (outer_class != Getattr(nn, "nested:outer"))) + if (symname && !(nnisclass && ((outer_class && (outer_class != Getattr(nn, "nested:outer"))) ||(extendmode && current_class && (current_class != Getattr(nn, "nested:outer")))))) { /* Comment this out for 1.3.28. We need to @@ -2974,11 +2975,10 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va move %ignore from using %rename to use %feature(ignore). - String *symname = Swig_name_make(templnode,0,$3,0,0); + String *symname = Swig_name_make(templnode, 0, symname, 0, 0); */ - String *symname = NewString($3); - Swig_cparse_template_expand(templnode,symname,temparms,tscope); - Setattr(templnode,"sym:name",symname); + Swig_cparse_template_expand(templnode, symname, temparms, tscope); + Setattr(templnode, "sym:name", symname); } else { static int cnt = 0; String *nname = NewStringf("__dummy_%d__", cnt++); @@ -2987,7 +2987,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va SetFlag(templnode,"hidden"); Delete(nname); Setattr(templnode,"feature:onlychildren", "typemap,typemapitem,typemapcopy,typedef,types,fragment,apply"); - if ($3) { + if (symname) { Swig_warning(WARN_PARSE_NESTED_TEMPLATE, cparse_file, cparse_line, "Named nested template instantiations not supported. Processing as if no name was given to %%template().\n"); } } @@ -3106,6 +3106,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Swig_symbol_setscope(tscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); + Delete(symname); } ; diff --git a/Source/CParse/templ.c b/Source/CParse/templ.c index 0dec21586..b02df8d05 100644 --- a/Source/CParse/templ.c +++ b/Source/CParse/templ.c @@ -605,7 +605,7 @@ static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const * Search for a template that matches name with given parameters. * ----------------------------------------------------------------------------- */ -static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { +static Node *template_locate(String *name, Parm *tparms, String *symname, Symtab *tscope) { Node *n = 0; String *tname = 0; Node *templ; @@ -626,7 +626,10 @@ static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { tname = Copy(name); SwigType_add_template(tname, tparms); Printf(stdout, "\n"); - Swig_diagnostic(cparse_file, cparse_line, "template_debug: Searching for match to: '%s'\n", tname); + if (symname) + Swig_diagnostic(cparse_file, cparse_line, "Template debug: Searching for match to: '%s' for instantiation of template named '%s'\n", tname, symname); + else + Swig_diagnostic(cparse_file, cparse_line, "Template debug: Searching for match to: '%s' for instantiation of empty template\n", tname); Delete(tname); tname = 0; } @@ -682,11 +685,39 @@ static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { } tn = Getattr(n, "template"); if (tn) { - if (template_debug) { - Printf(stdout, " previous instantiation found: '%s'\n", Getattr(n, "name")); + /* Previously wrapped by a template instantiation */ + Node *previous_named_instantiation = GetFlag(n, "hidden") ? Getattr(n, "csym:nextSibling") : n; /* "hidden" is set when "sym:name" is a __dummy_ name */ + if (!symname) { + /* Quietly ignore empty template instantiations if there is a previous (empty or non-empty) template instantiation */ + if (template_debug) { + if (previous_named_instantiation) + Printf(stdout, " previous instantiation with name '%s' found: '%s' - duplicate empty template instantiation ignored\n", Getattr(previous_named_instantiation, "sym:name"), Getattr(n, "name")); + else + Printf(stdout, " previous empty template instantiation found: '%s' - duplicate empty template instantiation ignored\n", Getattr(n, "name")); + } + return 0; } + /* Accept a second instantiation only if previous template instantiation is empty */ + if (previous_named_instantiation) { + String *previous_name = Getattr(previous_named_instantiation, "name"); + String *previous_symname = Getattr(previous_named_instantiation, "sym:name"); + String *unprocessed_tname = Copy(name); + SwigType_add_template(unprocessed_tname, tparms); + + if (template_debug) + Printf(stdout, " previous instantiation with name '%s' found: '%s' - duplicate instantiation ignored\n", previous_symname, Getattr(n, "name")); + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_TYPE_REDEFINED, cparse_file, cparse_line, "Duplicate template instantiation of '%s' with name '%s' ignored,\n", SwigType_namestr(unprocessed_tname), symname); + Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "previous instantiation of '%s' with name '%s'.\n", SwigType_namestr(previous_name), previous_symname); + SWIG_WARN_NODE_END(n); + + Delete(unprocessed_tname); + return 0; + } + if (template_debug) + Printf(stdout, " previous empty template instantiation found: '%s' - using as duplicate instantiation overrides empty template instantiation\n", Getattr(n, "name")); n = tn; - goto success; /* Previously wrapped by a template instantiation */ + goto success; } Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n)); Delete(tname); @@ -929,8 +960,8 @@ success: * template exists. * ----------------------------------------------------------------------------- */ -Node *Swig_cparse_template_locate(String *name, Parm *tparms, Symtab *tscope) { - Node *n = template_locate(name, tparms, tscope); /* this function does what we want for templated classes */ +Node *Swig_cparse_template_locate(String *name, Parm *tparms, String *symname, Symtab *tscope) { + Node *n = template_locate(name, tparms, symname, tscope); /* this function does what we want for templated classes */ if (n) { String *nodeType = nodeType(n); diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index 4a2a9df90..83ec8ad72 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -446,6 +446,7 @@ class TypePass:private Dispatcher { SwigType_typedef_class(fname); scopename = Copy(fname); } else { + // Does this code ever get executed ?? Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Template '%s' was already wrapped,\n", SwigType_namestr(name)); Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous wrap of '%s'.\n", SwigType_namestr(Getattr(cn, "name"))); scopename = 0;