Fix handling of abstract base classes nested inside templates

Code handling %template in the parser created a totally new top-level
module child of namespace type when handling templates inside a
namespace and copied the nodes from the previously parsed C++ template
declaration to it. However copies of this node kept their original
values of "abstracts" attribute, which contained pointers to the classes
in the original template declaration, i.e. outside of the subtree
created for the instantiated template. This, in turn, meant that during
the types resolution pass, the code in TypePass did not update the types
used in the methods of the classes appearing in the "abstracts" List,
even though it did update the types for the children of the instantiated
template subtree.

And this finally resulted in wrongly detecting overridden virtual
methods as abstract in Allocate::is_abstract_inherit() during the next
pass, as the signatures of the overridden method -- using resolved types
-- and of the method from the class pointed to by "abstract" -- using
the original types from C++ code -- didn't match.

Resolve this simply by not copying "abstracts" attributes when creating
the template subtree and doing another pass over this tree to recreate
them using the new nodes, just as it's already done for "defaultargs"
attribute, presumably for similar reasons. Note that doing another pass
over the tree is not as efficient as doing everything in a single pass,
but merging the new update_abstracts() with update_defaultargs() is not
completely obvious, so for now keep it simple and optimize it later if
necessary.

Also, add a test checking for the situation described above.

Closes #1353.
This commit is contained in:
Vadim Zeitlin 2018-11-21 00:07:14 +01:00
commit 30bb977a64
5 changed files with 79 additions and 0 deletions

View file

@ -166,6 +166,11 @@ static Node *copy_node(Node *n) {
Setattr(nn, "needs_defaultargs", "1");
continue;
}
/* same for abstracts, which contains pointers to the source node children, and so will need to be patch too */
if (strcmp(ckey,"abstracts") == 0) {
SetFlag(nn, "needs_abstracts");
continue;
}
/* Looks okay. Just copy the data using Copy */
ci = Copy(k.item);
Setattr(nn, key, ci);
@ -788,6 +793,22 @@ static List *pure_abstracts(Node *n) {
return abstracts;
}
/* Recompute the "abstracts" attribute for the classes in instantiated templates, similarly to update_defaultargs() above. */
static void update_abstracts(Node *n) {
for (; n; n = nextSibling(n)) {
Node* const child = firstChild(n);
if (!child)
continue;
update_abstracts(child);
if (Getattr(n, "needs_abstracts")) {
Setattr(n, "abstracts", pure_abstracts(child));
Delattr(n, "needs_abstracts");
}
}
}
/* Make a classname */
static String *make_class_name(String *name) {
@ -3056,6 +3077,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions. If a templated class there will never be a sibling. */
}
update_defaultargs(linkliststart);
update_abstracts(linkliststart);
}
Swig_symbol_setscope(tscope);
Delete(Namespaceprefix);