diff --git a/CHANGES.current b/CHANGES.current index 0170592f4..fb79c1875 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,13 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.2.0 (in progress) =========================== +2023-07-29: wsfulton + https://sourceforge.net/p/swig/bugs/678/ + Fix %copyctor used on class hierarchies with non-const copy + constructors. Previously SWIG always attempted to call a copy + constructor taking a const reference parameter instead of a + non-const reference parameter. + 2023-07-28: wsfulton [#2541] Fix overloading of templated constructors and %copyctor. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index c33d8ac55..649525585 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -150,6 +150,7 @@ CPP_TEST_CASES += \ constant_pointers \ constover \ constructor_copy \ + constructor_copy_non_const \ constructor_exception \ constructor_explicit \ constructor_ignore \ diff --git a/Examples/test-suite/constructor_copy_non_const.i b/Examples/test-suite/constructor_copy_non_const.i new file mode 100644 index 000000000..a8b9b09c8 --- /dev/null +++ b/Examples/test-suite/constructor_copy_non_const.i @@ -0,0 +1,71 @@ +%module(ruby_minherit="1") constructor_copy_non_const + +// Tests %copyctor and non-const copy constructors in inheritance chain + +%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, + SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, + SWIGWARN_D_MULTIPLE_INHERITANCE, + SWIGWARN_PHP_MULTIPLE_INHERITANCE) CCDerived; /* C#, D, Java, PHP multiple inheritance */ +%warnfilter(SWIGWARN_JAVA_MULTIPLE_INHERITANCE, + SWIGWARN_CSHARP_MULTIPLE_INHERITANCE, + SWIGWARN_D_MULTIPLE_INHERITANCE, + SWIGWARN_PHP_MULTIPLE_INHERITANCE) CCProtectedDerived; /* C#, D, Java, PHP multiple inheritance */ + +%inline %{ + struct CCBase1 { + CCBase1() {} + }; +%} + +%copyctor; + +%inline %{ + struct CCBase2 { + CCBase2() {} + CCBase2(CCBase2& other) {} // non-const copyctor + }; + + struct CCDerived : CCBase1, CCBase2 { + CCDerived() {} + // implicitly declared non-const copyctor + }; + struct CCMoreDerived : CCDerived { + // implicitly declared default ctor + // implicitly declared non-const copyctor + }; + struct CCMoreDerived2 : CCDerived { + CCMoreDerived2() {} + CCMoreDerived2(const CCMoreDerived2& other) {} // const copyctor + }; + struct CCMoreMoreDerived2 : CCMoreDerived2 { + // implicitly declared default ctor + // implicitly declared const copyctor + }; +%} + + +// Repeat but with protected non-const copyctor +%inline %{ + struct CCProtectedBase2 { + CCProtectedBase2() {} + protected: + CCProtectedBase2(CCProtectedBase2& other) {} // non-const copyctor + }; + + struct CCProtectedDerived : CCBase1, CCProtectedBase2 { + CCProtectedDerived() {} + // implicitly declared non-const copyctor + }; + struct CCProtectedMoreDerived : CCProtectedDerived { + // implicitly declared default ctor + // implicitly declared non-const copyctor + }; + struct CCProtectedMoreDerived2 : CCProtectedDerived { + CCProtectedMoreDerived2() {} + CCProtectedMoreDerived2(const CCProtectedMoreDerived2& other) {} // const copyctor + }; + struct CCProtectedMoreMoreDerived2 : CCProtectedMoreDerived2 { + // implicitly declared default ctor + // implicitly declared const copyctor + }; +%} diff --git a/Examples/test-suite/java/constructor_copy_non_const_runme.java b/Examples/test-suite/java/constructor_copy_non_const_runme.java new file mode 100644 index 000000000..8ed86f769 --- /dev/null +++ b/Examples/test-suite/java/constructor_copy_non_const_runme.java @@ -0,0 +1,30 @@ +import constructor_copy_non_const.*; + +public class constructor_copy_non_const_runme { + + static { + try { + System.loadLibrary("constructor_copy_non_const"); + } 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[]) { + { + CCBase2 ccb2 = new CCBase2(new CCBase2()); + CCDerived ccd = new CCDerived(new CCDerived()); + CCMoreDerived ccmd = new CCMoreDerived(new CCMoreDerived()); + CCMoreDerived2 ccmd2 = new CCMoreDerived2(new CCMoreDerived2()); + CCMoreMoreDerived2 ccmmd2 = new CCMoreMoreDerived2(new CCMoreMoreDerived2()); + } + { + // no copy ctor CCProtectedBase2 + CCProtectedDerived ccd = new CCProtectedDerived(new CCProtectedDerived()); + CCProtectedMoreDerived ccmd = new CCProtectedMoreDerived(new CCProtectedMoreDerived()); + CCProtectedMoreDerived2 ccmd2 = new CCProtectedMoreDerived2(new CCProtectedMoreDerived2()); + CCProtectedMoreMoreDerived2 ccmmd2 = new CCProtectedMoreMoreDerived2(new CCProtectedMoreMoreDerived2()); + } + } +} diff --git a/Examples/test-suite/python/constructor_copy_non_const_runme.py b/Examples/test-suite/python/constructor_copy_non_const_runme.py new file mode 100644 index 000000000..7a29d8973 --- /dev/null +++ b/Examples/test-suite/python/constructor_copy_non_const_runme.py @@ -0,0 +1,13 @@ +from constructor_copy_non_const import * + +ccb2 = CCBase2(CCBase2()) +ccd = CCDerived(CCDerived()) +ccmd = CCMoreDerived(CCMoreDerived()) +ccmd2 = CCMoreDerived2(CCMoreDerived2()) +ccmmd2 = CCMoreMoreDerived2(CCMoreMoreDerived2()) + +# no copy ctor CCProtectedBase2 +ccd = CCProtectedDerived(CCProtectedDerived()) +ccmd = CCProtectedMoreDerived(CCProtectedMoreDerived()) +ccmd2 = CCProtectedMoreDerived2(CCProtectedMoreDerived2()) +ccmmd2 = CCProtectedMoreMoreDerived2(CCProtectedMoreMoreDerived2()) diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index 59b17c6eb..03187703d 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -651,11 +651,13 @@ Allocate(): if (!Getattr(n, "allocate:has_copy_constructor")) { if (Getattr(n, "abstracts")) { Delattr(n, "allocate:copy_constructor"); + Delattr(n, "allocate:copy_constructor_non_const"); } if (!Getattr(n, "allocate:copy_constructor")) { /* Check base classes */ List *bases = Getattr(n, "allbases"); int allows_copy = 1; + int must_be_copy_non_const = 0; for (int i = 0; i < Len(bases); i++) { Node *n = Getitem(bases, i); @@ -663,10 +665,16 @@ Allocate(): if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) { allows_copy = 0; } + if (Getattr(n, "allocate:copy_constructor_non_const") || (Getattr(n, "allocate:copy_base_constructor_non_const"))) { + must_be_copy_non_const = 1; + } } if (allows_copy) { Setattr(n, "allocate:copy_constructor", "1"); } + if (must_be_copy_non_const) { + Setattr(n, "allocate:copy_constructor_non_const", "1"); + } } } @@ -1164,6 +1172,7 @@ Allocate(): if (parms && (ParmList_numrequired(parms) == 1)) { /* Look for a few cases. X(const X &), X(X &), X(X *) */ int copy_constructor = 0; + int copy_constructor_non_const = 0; SwigType *type = Getattr(inclass, "name"); String *tn = NewStringf("r.q(const).%s", type); String *cc = SwigType_typedef_resolve_all(tn); @@ -1183,6 +1192,7 @@ Allocate(): cc = NewStringf("r.%s", Getattr(inclass, "name")); if (Strcmp(cc, Getattr(parms, "type")) == 0) { copy_constructor = 1; + copy_constructor_non_const = 1; } else { Delete(cc); cc = NewStringf("p.%s", Getattr(inclass, "name")); @@ -1205,6 +1215,15 @@ Allocate(): } else if (access_mode == PROTECTED) { Setattr(inclass, "allocate:copy_base_constructor", "1"); } + if (copy_constructor_non_const) { + Setattr(n, "copy_constructor_non_const", "1"); + Setattr(inclass, "allocate:has_copy_constructor_non_const", "1"); + if (access_mode == PUBLIC) { + Setattr(inclass, "allocate:copy_constructor_non_const", "1"); + } else if (access_mode == PROTECTED) { + Setattr(inclass, "allocate:copy_base_constructor_non_const", "1"); + } + } } } return SWIG_OK; @@ -1237,11 +1256,12 @@ static void addCopyConstructor(Node *n) { Setfile(cn, Getfile(n)); Setline(cn, Getline(n)); + int copy_constructor_non_const = GetFlag(n, "allocate:copy_constructor_non_const"); String *cname = Getattr(n, "name"); SwigType *type = Copy(cname); String *lastname = Swig_scopename_last(cname); String *name = SwigType_templateprefix(lastname); - String *cc = NewStringf("r.q(const).%s", type); + String *cc = NewStringf(copy_constructor_non_const ? "r.%s" : "r.q(const).%s", type); String *decl = NewStringf("f(%s).", cc); String *oldname = Getattr(n, "sym:name");