mirror of https://github.com/swig/swig
Fix C++11 using declarations for inheriting implicit base constructors
Parser no longer checks for a declared constructor when handling a using declaration in order to correct the name as it won't find implicitly declared constructors. Now it checks that a using declaration is for something that looks like a constructor instead by checking the immediate base classes for allowed constructors.
This commit is contained in:
parent
655d43769e
commit
feb8e2e641
|
@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-07-13: wsfulton
|
||||
C++11 using declarations for inheriting constructors support now
|
||||
also includes inheriting implicitly defined default constructors
|
||||
from the base class.
|
||||
|
||||
2023-07-04: wsfulton
|
||||
#2641 Add support for C++11 using declarations for inheriting
|
||||
constructors.
|
||||
|
|
|
@ -40,6 +40,15 @@ struct PublicDerived4 : PublicBase4 {
|
|||
using PublicBase4::meth;
|
||||
};
|
||||
|
||||
struct PublicBase5 {
|
||||
// implicit constructor
|
||||
void meth() {}
|
||||
};
|
||||
struct PublicDerived5 : PublicBase5 {
|
||||
using PublicBase5::PublicBase5;
|
||||
using PublicBase5::meth;
|
||||
};
|
||||
|
||||
// Protected base constructors
|
||||
struct ProtectedBase1 {
|
||||
protected:
|
||||
|
@ -83,6 +92,16 @@ struct ProtectedDerived4 : ProtectedBase4 {
|
|||
using ProtectedBase4::meth;
|
||||
};
|
||||
|
||||
struct ProtectedBase5 {
|
||||
// implicit constructor
|
||||
protected:
|
||||
void meth() {}
|
||||
};
|
||||
struct ProtectedDerived5 : ProtectedBase5 {
|
||||
using ProtectedBase5::ProtectedBase5;
|
||||
using ProtectedBase5::meth;
|
||||
};
|
||||
|
||||
// Mix of public and overloaded constructors
|
||||
struct MixedBase1 {
|
||||
MixedBase1(int i, const char* s) {}
|
||||
|
@ -151,6 +170,40 @@ struct MixedDerived3d : MixedBase3 {
|
|||
using MixedBase3::meth;
|
||||
};
|
||||
|
||||
struct MixedBase4 {
|
||||
void meth() {}
|
||||
};
|
||||
struct MixedDerived4a : MixedBase4 {
|
||||
MixedDerived4a(int i, const char* s) {}
|
||||
using MixedBase4::MixedBase4;
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
struct MixedDerived4b : MixedBase4 {
|
||||
using MixedBase4::MixedBase4;
|
||||
MixedDerived4b(int i, const char* s) {}
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
struct MixedDerived4c : MixedBase4 {
|
||||
using MixedBase4::MixedBase4;
|
||||
MixedDerived4c(int ii) {}
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
struct MixedDerived4d : MixedBase4 {
|
||||
MixedDerived4d(int ii) {}
|
||||
using MixedBase4::MixedBase4;
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
struct MixedDerived4e : MixedBase4 {
|
||||
MixedDerived4e() {}
|
||||
using MixedBase4::MixedBase4;
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
struct MixedDerived4f : MixedBase4 {
|
||||
using MixedBase4::MixedBase4;
|
||||
MixedDerived4f() {}
|
||||
using MixedBase4::meth;
|
||||
};
|
||||
|
||||
// Mix of protected base constructors and overloading
|
||||
struct ProotBase1 {
|
||||
ProotBase1() {}
|
||||
|
@ -285,11 +338,18 @@ struct TemplatePublicDerived4 : PublicBase4 {
|
|||
using PublicBase4::PublicBase4;
|
||||
using PublicBase4::meth;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TemplatePublicDerived5 : PublicBase5 {
|
||||
using PublicBase5::PublicBase5;
|
||||
using PublicBase5::meth;
|
||||
};
|
||||
%}
|
||||
%template(TemplatePublicDerived1Int) TemplatePublicDerived1<int>;
|
||||
%template(TemplatePublicDerived2Int) TemplatePublicDerived2<int>;
|
||||
%template(TemplatePublicDerived3Int) TemplatePublicDerived3<int>;
|
||||
%template(TemplatePublicDerived4Int) TemplatePublicDerived4<int>;
|
||||
%template(TemplatePublicDerived5Int) TemplatePublicDerived5<int>;
|
||||
|
||||
%inline %{
|
||||
// Templates and public base constructors (derive from template)
|
||||
|
@ -318,12 +378,19 @@ struct TemplPublicBase4 {
|
|||
TemplPublicBase4() = default;
|
||||
void meth() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TemplPublicBase5 {
|
||||
// implicit constructor
|
||||
void meth() {}
|
||||
};
|
||||
%}
|
||||
|
||||
%template(TemplPublicBase1Int) TemplPublicBase1<int>;
|
||||
%template(TemplPublicBase2Int) TemplPublicBase2<int>;
|
||||
%template(TemplPublicBase3Int) TemplPublicBase3<int>;
|
||||
%template(TemplPublicBase4Int) TemplPublicBase4<int>;
|
||||
%template(TemplPublicBase5Int) TemplPublicBase5<int>;
|
||||
|
||||
%inline %{
|
||||
template<typename T>
|
||||
|
@ -346,9 +413,15 @@ struct TemplPublicDerived4 : TemplPublicBase4<T> {
|
|||
using TemplPublicBase4<T>::TemplPublicBase4;
|
||||
using TemplPublicBase4<T>::meth;
|
||||
};
|
||||
template<typename T>
|
||||
struct TemplPublicDerived5 : TemplPublicBase5<T> {
|
||||
using TemplPublicBase5<T>::TemplPublicBase5;
|
||||
using TemplPublicBase5<T>::meth;
|
||||
};
|
||||
%}
|
||||
|
||||
%template(TemplPublicDerived1Int) TemplPublicDerived1<int>;
|
||||
%template(TemplPublicDerived2Int) TemplPublicDerived2<int>;
|
||||
%template(TemplPublicDerived3Int) TemplPublicDerived3<int>;
|
||||
%template(TemplPublicDerived4Int) TemplPublicDerived4<int>;
|
||||
%template(TemplPublicDerived5Int) TemplPublicDerived5<int>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
cpp_using_rename.i:20: Warning 315: Nothing known about 'Base::does_not_exist'.
|
||||
cpp_using_rename.i:18: Warning 526: Using declaration Base::use_me, with name 'use_me', is not actually using
|
||||
cpp_using_rename.i:10: Warning 526: the method from Base::use_me(int), with name 'UseMe', as the names are different.
|
||||
cpp_using_rename.i:19: Warning 526: Using declaration Base::use_me_too, with name 'UseMeToo', is not actually using
|
||||
cpp_using_rename.i:11: Warning 526: the method from Base::use_me_too(double) const, with name 'use_me_too', as the names are different.
|
||||
cpp_using_rename.i:19: Warning 526: Using declaration Base::use_me_too, with name 'UseMeToo', is not actually using
|
||||
cpp_using_rename.i:12: Warning 526: the method from Base::use_me_too(bool) const, with name 'use_me_too', as the names are different.
|
||||
cpp_using_rename.i:20: Warning 315: Nothing known about 'Base::does_not_exist'.
|
||||
|
|
|
@ -20,9 +20,11 @@ public class cpp11_using_constructor_runme {
|
|||
new PublicDerived3().meth();
|
||||
new PublicDerived3(0, "hi").meth();
|
||||
new PublicDerived4().meth();
|
||||
new PublicDerived5().meth();
|
||||
|
||||
// Protected base constructors
|
||||
// Cannot test these as the constructors are protected
|
||||
// Cannot test most of these as the constructors are protected
|
||||
new ProtectedDerived5();
|
||||
|
||||
// Mix of public and overloaded constructors
|
||||
new MixedDerived1a(0, "hi").meth();
|
||||
|
@ -56,6 +58,21 @@ public class cpp11_using_constructor_runme {
|
|||
new MixedDerived3d().meth();
|
||||
new MixedDerived3d(0).meth();
|
||||
|
||||
new MixedDerived4a(0, "hi").meth();
|
||||
new MixedDerived4a().meth();
|
||||
new MixedDerived4b(0, "hi").meth();
|
||||
new MixedDerived4b().meth();
|
||||
|
||||
new MixedDerived4c().meth();
|
||||
new MixedDerived4c(0).meth();
|
||||
|
||||
new MixedDerived4d().meth();
|
||||
new MixedDerived4d(0).meth();
|
||||
|
||||
new MixedDerived4e().meth();
|
||||
|
||||
new MixedDerived4f().meth();
|
||||
|
||||
// Mix of protected base constructors and overloading
|
||||
new ProotDerived1a().meth();
|
||||
|
||||
|
@ -98,6 +115,7 @@ public class cpp11_using_constructor_runme {
|
|||
new TemplatePublicDerived3Int().meth();
|
||||
new TemplatePublicDerived3Int(0, "hi").meth();
|
||||
new TemplatePublicDerived4Int().meth();
|
||||
new TemplatePublicDerived5Int().meth();
|
||||
|
||||
// Templates and public base constructors (derive from template)
|
||||
new TemplPublicDerived1Int(0, "hi").meth();
|
||||
|
@ -106,5 +124,6 @@ public class cpp11_using_constructor_runme {
|
|||
new TemplPublicDerived3Int().meth();
|
||||
new TemplPublicDerived3Int(0, "hi").meth();
|
||||
new TemplPublicDerived4Int().meth();
|
||||
new TemplPublicDerived5Int().meth();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,11 @@ a = PublicDerived2(0, "hi").meth()
|
|||
a = PublicDerived3().meth()
|
||||
a = PublicDerived3(0, "hi").meth()
|
||||
a = PublicDerived4().meth()
|
||||
a = PublicDerived5().meth()
|
||||
|
||||
# Protected base constructors
|
||||
# Cannot test these as the constructors are protected
|
||||
# Cannot test most of these as the constructors are protected
|
||||
ProtectedDerived5()
|
||||
|
||||
# Mix of public and overloaded constructors
|
||||
MixedDerived1a(0, "hi").meth()
|
||||
|
@ -44,6 +46,21 @@ MixedDerived3d(0, "hi").meth()
|
|||
MixedDerived3d().meth()
|
||||
MixedDerived3d(0).meth()
|
||||
|
||||
MixedDerived4a(0, "hi").meth()
|
||||
MixedDerived4a().meth()
|
||||
MixedDerived4b(0, "hi").meth()
|
||||
MixedDerived4b().meth()
|
||||
|
||||
MixedDerived4c().meth()
|
||||
MixedDerived4c(0).meth()
|
||||
|
||||
MixedDerived4d().meth()
|
||||
MixedDerived4d(0).meth()
|
||||
|
||||
MixedDerived4e().meth()
|
||||
|
||||
MixedDerived4f().meth()
|
||||
|
||||
# Mix of protected base constructors and overloading
|
||||
ProotDerived1a().meth()
|
||||
|
||||
|
@ -86,6 +103,7 @@ TemplatePublicDerived2Int(0, "hi").meth()
|
|||
TemplatePublicDerived3Int().meth()
|
||||
TemplatePublicDerived3Int(0, "hi").meth()
|
||||
TemplatePublicDerived4Int().meth()
|
||||
TemplatePublicDerived5Int().meth()
|
||||
|
||||
# Templates and public base constructors (derive from template)
|
||||
TemplPublicDerived1Int(0, "hi").meth()
|
||||
|
@ -94,3 +112,4 @@ TemplPublicDerived2Int(0, "hi").meth()
|
|||
TemplPublicDerived3Int().meth()
|
||||
TemplPublicDerived3Int(0, "hi").meth()
|
||||
TemplPublicDerived4Int().meth()
|
||||
TemplPublicDerived5Int().meth()
|
||||
|
|
|
@ -450,33 +450,20 @@ static void add_symbols(Node *n) {
|
|||
}
|
||||
Namespaceprefix = 0;
|
||||
} else if (Equal(nodeType(n), "using")) {
|
||||
Symtab *stab = Swig_symbol_current();
|
||||
String *uname = Getattr(n, "uname");
|
||||
Node *ns = Swig_symbol_clookup(uname, stab);
|
||||
String *ntype = 0;
|
||||
if (!ns && SwigType_istemplate(uname)) {
|
||||
String *tbase = SwigType_templateprefix(uname);
|
||||
String *uname_template = NewStringf("%s%s", tbase, SwigType_templatesuffix(uname));
|
||||
ns = Swig_symbol_clookup(uname_template, stab);
|
||||
if (!ns) {
|
||||
String *tmp = Swig_symbol_template_deftype(uname, 0);
|
||||
if (!Equal(tmp, uname)) {
|
||||
ns = Swig_symbol_clookup(tmp, stab);
|
||||
}
|
||||
Delete(tmp);
|
||||
}
|
||||
Delete(tbase);
|
||||
Delete(uname_template);
|
||||
}
|
||||
if (ns) {
|
||||
ntype = nodeType(ns);
|
||||
if (Equal(ntype, "constructor")) {
|
||||
/* The using declaration name for inheriting constructors is the base class constructor name
|
||||
* not the name provided by the using declaration. Correct it here. */
|
||||
String *stabname = Getattr(stab, "name");
|
||||
String *nname = SwigType_templateprefix(stabname);
|
||||
Node *cls = current_class ? current_class : currentOuterClass; /* Current class seems to vary depending on whether it is a template class or a plain class */
|
||||
String *nprefix = 0;
|
||||
String *nlast = 0;
|
||||
Swig_scopename_split(uname, &nprefix, &nlast);
|
||||
if (Swig_item_in_list(Getattr(cls, "baselist"), nprefix) || Swig_item_in_list(Getattr(cls, "protectedbaselist"), nprefix) || Swig_item_in_list(Getattr(cls, "privatebaselist"), nprefix)) {
|
||||
String *plain_name = SwigType_istemplate(nprefix) ? SwigType_templateprefix(nprefix) : nprefix;
|
||||
if (Equal(nlast, plain_name)) {
|
||||
/* Using declaration looks like it is using a constructor in an immediate base class - change the constructor name for this class.
|
||||
* C++11 requires using declarations for inheriting base constructors to be in the immediate base class.
|
||||
* Note that we don't try and look up the constructor in the base class as the constructor may be an implicit/implied constructor and hence not exist. */
|
||||
Symtab *stab = Swig_symbol_current();
|
||||
String *nname = Getattr(stab, "name");
|
||||
Setattr(n, "name", nname);
|
||||
Delete(nname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -800,8 +800,11 @@ Allocate():
|
|||
} else {
|
||||
ns = 0;
|
||||
}
|
||||
// Note that TypePass::usingDeclaration has warned when using member is not found (when ns is zero)
|
||||
if (ns) {
|
||||
if (!ns) {
|
||||
if (is_public(n)) {
|
||||
Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname")));
|
||||
}
|
||||
} else {
|
||||
String *ntype = nodeType(ns);
|
||||
if (Equal(ntype, "cdecl") || Equal(ntype, "constructor")) {
|
||||
if (!checkAttribute(ns, "storage", "typedef")) {
|
||||
|
|
|
@ -2081,9 +2081,9 @@ public:
|
|||
sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up
|
||||
|
||||
// Constructors will be treated specially
|
||||
const bool isCtor = (!Cmp(Getattr(sibl, "nodeType"), "constructor"));
|
||||
const bool isMethod = ( Cmp(Getattr(sibl, "ismember"), "1") == 0 &&
|
||||
(!isCtor) );
|
||||
String *siblNodeType = Getattr(sibl, "nodeType");
|
||||
const bool isCtor = (Equal(siblNodeType, "constructor"));
|
||||
const bool isMethod = (Equal(siblNodeType, "cdecl") && GetFlag(sibl, "ismember") && !isCtor);
|
||||
|
||||
// Construct real method name
|
||||
String* methodName = NewString("");
|
||||
|
@ -2103,7 +2103,7 @@ public:
|
|||
String *protoTypes = NewString("");
|
||||
do {
|
||||
Append( protoTypes, "\n\" ");
|
||||
if (!isCtor) {
|
||||
if (!isCtor && !Equal(siblNodeType, "using")) {
|
||||
SwigType *type = SwigType_str(Getattr(sibl, "type"), NULL);
|
||||
Printv(protoTypes, type, " ", NIL);
|
||||
Delete(type);
|
||||
|
|
|
@ -1004,11 +1004,8 @@ class TypePass:private Dispatcher {
|
|||
} else {
|
||||
ns = 0;
|
||||
}
|
||||
if (!ns) {
|
||||
if (is_public(n)) {
|
||||
Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname")));
|
||||
}
|
||||
} else {
|
||||
// Note that TypePass::usingDeclaration will warn when using member is not found (when ns is zero)
|
||||
if (ns) {
|
||||
/* 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);
|
||||
|
|
|
@ -1357,12 +1357,33 @@ String *Swig_pcre_version(void) {
|
|||
* Check if the function is an automatically generated
|
||||
* overload created because a method has default parameters.
|
||||
* ------------------------------------------------------------ */
|
||||
|
||||
int Swig_is_generated_overload(Node *n) {
|
||||
Node *base_method = Getattr(n, "sym:overloaded");
|
||||
Node *default_args = Getattr(n, "defaultargs");
|
||||
return ((base_method != NULL) && (default_args != NULL) && (base_method == default_args));
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_item_in_list()
|
||||
*
|
||||
* If the input name is the name of an item in the list, return the item
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
Node *Swig_item_in_list(List *list, const_String_or_char_ptr name) {
|
||||
Node *item = 0;
|
||||
if (list) {
|
||||
Iterator it;
|
||||
for (it = First(list); it.item; it = Next(it)) {
|
||||
if (Strcmp(name, it.item) == 0) {
|
||||
item = it.item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_init()
|
||||
*
|
||||
|
|
|
@ -339,6 +339,7 @@ extern int ParmList_is_compactdefargs(ParmList *p);
|
|||
|
||||
extern int Swig_value_wrapper_mode(int mode);
|
||||
extern int Swig_is_generated_overload(Node *n);
|
||||
extern Node *Swig_item_in_list(List *list, const String *name);
|
||||
|
||||
typedef enum { EMF_STANDARD, EMF_MICROSOFT } ErrorMessageFormat;
|
||||
|
||||
|
|
Loading…
Reference in New Issue