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:
William S Fulton 2023-07-13 17:43:00 +01:00
parent 655d43769e
commit feb8e2e641
11 changed files with 164 additions and 39 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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")) {

View File

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

View File

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

View File

@ -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()
*

View File

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