mirror of https://github.com/swig/swig
Add support for C++11 using declarations for inheriting constructors
Closes #2641
This commit is contained in:
parent
3ef3f39516
commit
61e60271fe
|
@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-07-04: wsfulton
|
||||
#2641 Add support for C++11 using declarations for inheriting
|
||||
constructors.
|
||||
|
||||
2023-06-30: wsfulton
|
||||
#2640 Fix syntax error parsing an expression which calls a function
|
||||
with no parameters within additional brackets.
|
||||
|
|
|
@ -73,8 +73,7 @@
|
|||
|
||||
|
||||
<p>This chapter gives you a brief overview about the SWIG
|
||||
implementation of the C++11 standard. This part of SWIG is still a work in
|
||||
progress.
|
||||
implementation of the C++11 standard.
|
||||
</p>
|
||||
<p>SWIG supports the new C++ syntax changes with some minor limitations
|
||||
in some areas such as decltype expressions and variadic templates. Wrappers for the
|
||||
|
@ -863,12 +862,9 @@ where peer constructors can be called. SWIG handles this without any issue.
|
|||
|
||||
<p>
|
||||
The second improvement is constructor inheritance via a <tt>using</tt> declaration.
|
||||
This is parsed correctly, but the additional constructors are not currently added to the derived proxy class in the target language.
|
||||
An example is shown below:
|
||||
<!--
|
||||
The extra constructors provided by the <tt>using</tt> syntax will add the appropriate constructors into the target language proxy derived classes.
|
||||
In the example below a wrapper for the <tt>DerivedClass(int)</tt> is added to <tt>DerivedClass</tt>:
|
||||
-->
|
||||
The extra constructors provided by the <tt>using</tt> declaration will add the appropriate constructors into the target language proxy derived classes.
|
||||
In the example below a wrapper for the <tt>DerivedClass(int)</tt> constructor is added to <tt>DerivedClass</tt>:
|
||||
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
|
@ -883,6 +879,10 @@ class DerivedClass: public BaseClass {
|
|||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
<b>Compatibility note:</b> SWIG-4.2.0 was the first version to generate wrappers for constructors inherited via <tt>using</tt> declarations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The final part is member initialization at the site of the declaration.
|
||||
This kind of initialization is handled by SWIG.
|
||||
|
|
|
@ -5347,6 +5347,11 @@ you wrap this code in Python, the module works just like you would expect:
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The C++11 standard supports using declarations for inheriting constructors and this is covered in
|
||||
<a href="CPlusPlus11_object_construction_improvement">Object construction improvement</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
C++ <tt>using</tt> declarations can also be used to change access when applicable.
|
||||
For example, protected methods in a base class can be made public in a derived class:
|
||||
|
|
|
@ -637,6 +637,7 @@ CPP11_TEST_CASES += \
|
|||
cpp11_uniform_initialization \
|
||||
cpp11_unrestricted_unions \
|
||||
cpp11_userdefined_literals \
|
||||
cpp11_using_constructor \
|
||||
cpp11_using_typedef_struct \
|
||||
cpp11_variadic_function_templates \
|
||||
cpp11_variadic_templates \
|
||||
|
|
|
@ -10,6 +10,7 @@ private:
|
|||
int _val;
|
||||
public:
|
||||
BaseClass(int iValue) { _val = iValue; }
|
||||
int retrieveValue() { return _val; }
|
||||
};
|
||||
|
||||
// Constructor inheritance via using declaration
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import cpp11_inheriting_constructors.*;
|
||||
|
||||
public class cpp11_inheriting_constructors_runme {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("cpp11_inheriting_constructors");
|
||||
} 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[]) {
|
||||
// Constructor inheritance via using declaration
|
||||
DerivedClass d = new DerivedClass(10);
|
||||
if (d.retrieveValue() != 10)
|
||||
throw new RuntimeException("retrieveValue() failed");
|
||||
|
||||
// Member initialization at the site of the declaration
|
||||
SomeClass s = new SomeClass();
|
||||
if (s.getValue() != 5)
|
||||
throw new RuntimeException("s.value failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
import cpp11_using_constructor.*;
|
||||
|
||||
public class cpp11_using_constructor_runme {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("cpp11_using_constructor");
|
||||
} 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[]) {
|
||||
// Public base constructors
|
||||
new PublicDerived1(0, "hi").meth();
|
||||
new PublicDerived2().meth();
|
||||
new PublicDerived2(0, "hi").meth();
|
||||
new PublicDerived3().meth();
|
||||
new PublicDerived3(0, "hi").meth();
|
||||
new PublicDerived4().meth();
|
||||
|
||||
// Protected base constructors
|
||||
// Cannot test these as the constructors are protected
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
from cpp11_inheriting_constructors import *
|
||||
|
||||
# Constructor inheritance via using declaration
|
||||
d = DerivedClass(10)
|
||||
if d.retrieveValue() != 10:
|
||||
raise RuntimeError("retrieveValue() failed");
|
||||
|
||||
# Member initialization at the site of the declaration
|
||||
s = SomeClass()
|
||||
if s.value != 5:
|
||||
raise RuntimeError("s.value failed");
|
|
@ -0,0 +1,13 @@
|
|||
from cpp11_using_constructor import *
|
||||
|
||||
|
||||
# Public base constructors
|
||||
a = PublicDerived1(0, "hi").meth()
|
||||
a = PublicDerived2().meth()
|
||||
a = PublicDerived2(0, "hi").meth()
|
||||
a = PublicDerived3().meth()
|
||||
a = PublicDerived3(0, "hi").meth()
|
||||
a = PublicDerived4().meth()
|
||||
|
||||
# Protected base constructors
|
||||
# Cannot test these as the constructors are protected
|
|
@ -499,7 +499,10 @@ static void add_symbols(Node *n) {
|
|||
} else {
|
||||
Setattr(n, "access", "public");
|
||||
}
|
||||
} else if (extendmode && !inclass) {
|
||||
Setattr(n, "access", "public");
|
||||
}
|
||||
|
||||
if (Getattr(n,"sym:name")) {
|
||||
n = nextSibling(n);
|
||||
continue;
|
||||
|
|
|
@ -755,11 +755,13 @@ Allocate():
|
|||
|
||||
Node *c = 0;
|
||||
for (c = firstChild(n); c; c = nextSibling(c)) {
|
||||
if (Strcmp(nodeType(c), "cdecl") == 0) {
|
||||
if (Equal(nodeType(c), "cdecl")) {
|
||||
process_exceptions(c);
|
||||
|
||||
if (inclass)
|
||||
class_member_is_defined_in_bases(c, inclass);
|
||||
} else if (Equal(nodeType(c), "constructor")) {
|
||||
constructorDeclaration(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -868,21 +870,22 @@ Allocate():
|
|||
if (!inclass)
|
||||
return SWIG_OK;
|
||||
Parm *parms = Getattr(n, "parms");
|
||||
AccessMode access_mode = accessModeFromString(Getattr(n, "access"));
|
||||
|
||||
process_exceptions(n);
|
||||
if (!extendmode) {
|
||||
if (!ParmList_numrequired(parms)) {
|
||||
/* Class does define a default constructor */
|
||||
/* However, we had better see where it is defined */
|
||||
if (cplus_mode == PUBLIC) {
|
||||
if (access_mode == PUBLIC) {
|
||||
Setattr(inclass, "allocate:default_constructor", "1");
|
||||
} else if (cplus_mode == PROTECTED) {
|
||||
} else if (access_mode == PROTECTED) {
|
||||
Setattr(inclass, "allocate:default_base_constructor", "1");
|
||||
}
|
||||
}
|
||||
/* Class defines some kind of constructor. May or may not be public */
|
||||
Setattr(inclass, "allocate:has_constructor", "1");
|
||||
if (cplus_mode == PUBLIC) {
|
||||
if (access_mode == PUBLIC) {
|
||||
Setattr(inclass, "allocate:public_constructor", "1");
|
||||
}
|
||||
} else {
|
||||
|
@ -931,9 +934,9 @@ Allocate():
|
|||
if (copy_constructor) {
|
||||
Setattr(n, "copy_constructor", "1");
|
||||
Setattr(inclass, "allocate:has_copy_constructor", "1");
|
||||
if (cplus_mode == PUBLIC) {
|
||||
if (access_mode == PUBLIC) {
|
||||
Setattr(inclass, "allocate:copy_constructor", "1");
|
||||
} else if (cplus_mode == PROTECTED) {
|
||||
} else if (access_mode == PROTECTED) {
|
||||
Setattr(inclass, "allocate:copy_base_constructor", "1");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,94 +221,138 @@ int Dispatcher::emit_children(Node *n) {
|
|||
int Dispatcher::defaultHandler(Node *) {
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
int Dispatcher::extendDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::applyDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::clearDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::constantDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::fragmentDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::importDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::includeDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::insertDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::moduleDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::nativeDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::pragmaDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::typemapDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::typemapitemDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::typemapcopyDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::typesDirective(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::cDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::externDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::enumDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::enumvalueDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::enumforwardDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::classDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::templateDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::lambdaDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::classforwardDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::constructorDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::destructorDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::accessDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::usingDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
int Dispatcher::namespaceDeclaration(Node *n) {
|
||||
return defaultHandler(n);
|
||||
}
|
||||
|
||||
Dispatcher::AccessMode Dispatcher::accessModeFromString(String *access) {
|
||||
Dispatcher::AccessMode mode = PUBLIC;
|
||||
if (Cmp(access, "public") == 0) {
|
||||
mode = PUBLIC;
|
||||
} else if (Cmp(access, "private") == 0) {
|
||||
mode = PRIVATE;
|
||||
} else if (Cmp(access, "protected") == 0) {
|
||||
mode = PROTECTED;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
/* Allocators */
|
||||
Language::Language():
|
||||
none_comparison(NewString("$arg != 0")),
|
||||
|
@ -2675,7 +2719,7 @@ int Language::constructorDeclaration(Node *n) {
|
|||
Setattr(CurrentClass, "sym:cleanconstructor", "1");
|
||||
}
|
||||
|
||||
if ((cplus_mode != PUBLIC)) {
|
||||
if (!is_public(n)) {
|
||||
/* check only for director classes */
|
||||
if (!Swig_directorclass(CurrentClass) || !need_nonpublic_ctor(n))
|
||||
return SWIG_NOWRAP;
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
|
||||
protected:
|
||||
AccessMode cplus_mode;
|
||||
AccessMode accessModeFromString(String *access);
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
|
|
@ -1012,7 +1012,7 @@ class TypePass:private Dispatcher {
|
|||
/* Only a single symbol is being used. There are only a few symbols that
|
||||
we actually care about. These are typedef, class declarations, and enum */
|
||||
String *ntype = nodeType(ns);
|
||||
if (Strcmp(ntype, "cdecl") == 0) {
|
||||
if (Equal(ntype, "cdecl") || Equal(ntype, "constructor")) {
|
||||
if (checkAttribute(ns, "storage", "typedef")) {
|
||||
/* A typedef declaration */
|
||||
String *uname = Getattr(n, "uname");
|
||||
|
@ -1040,7 +1040,7 @@ class TypePass:private Dispatcher {
|
|||
}
|
||||
|
||||
while (c) {
|
||||
if (Strcmp(nodeType(c), "cdecl") == 0) {
|
||||
if (Strcmp(nodeType(c), ntype) == 0) {
|
||||
if (!(Swig_storage_isstatic(c)
|
||||
|| checkAttribute(c, "storage", "typedef")
|
||||
|| Strstr(Getattr(c, "storage"), "friend")
|
||||
|
@ -1074,8 +1074,6 @@ class TypePass:private Dispatcher {
|
|||
Node *nn = copyNode(c);
|
||||
Setfile(nn, Getfile(n));
|
||||
Setline(nn, Getline(n));
|
||||
Delattr(nn, "access"); // access might be different from the method in the base class
|
||||
Setattr(nn, "access", Getattr(n, "access"));
|
||||
if (!Getattr(nn, "sym:name"))
|
||||
Setattr(nn, "sym:name", symname);
|
||||
Symtab *st = Getattr(n, "sym:symtab");
|
||||
|
@ -1083,7 +1081,19 @@ class TypePass:private Dispatcher {
|
|||
Setattr(nn, "sym:symtab", st);
|
||||
// The real parent is the "using" declaration node, but subsequent code generally handles
|
||||
// and expects a class member to point to the parent class node
|
||||
Setattr(nn, "parentNode", parentNode(n));
|
||||
Node *parent = parentNode(n);
|
||||
Setattr(nn, "parentNode", parent);
|
||||
|
||||
if (Equal(ntype, "constructor")) {
|
||||
Setattr(nn, "name", Getattr(parent, "name"));
|
||||
Setattr(nn, "sym:name", Getattr(parent, "sym:name"));
|
||||
// Note that the added constructor's access is the same as that of
|
||||
// the base class' constructor not of the using declaration
|
||||
} else {
|
||||
// Access might be different from the method in the base class
|
||||
Delattr(nn, "access");
|
||||
Setattr(nn, "access", Getattr(n, "access"));
|
||||
}
|
||||
|
||||
if (!GetFlag(nn, "feature:ignore")) {
|
||||
ParmList *parms = CopyParmList(Getattr(c, "parms"));
|
||||
|
|
Loading…
Reference in New Issue