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.
This commit is contained in:
William S Fulton 2022-11-18 18:49:48 +00:00
commit 4729cf2b1f
16 changed files with 283 additions and 55 deletions

View file

@ -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

View file

@ -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);
}
;

View file

@ -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);

View file

@ -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;