diff --git a/CHANGES.current b/CHANGES.current index 9adfa8ad0..3a10743e5 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-07-05: ianlancetaylor + [Go] #2245 Handle NULL pointers for string* conversions. + Rearrange generation of director methods and rename + receiver argument from p to swig_p. + 2022-07-03: wsfulton Performane optimisation for directors for classes passed by value. The directorin typemaps in the director methods now use std::move on the input parameter when diff --git a/Examples/test-suite/go/go_director_inout_runme.go b/Examples/test-suite/go/go_director_inout_runme.go index 55f32dfc3..6b68543a2 100644 --- a/Examples/test-suite/go/go_director_inout_runme.go +++ b/Examples/test-suite/go/go_director_inout_runme.go @@ -67,6 +67,9 @@ func main() { a.CallS4([]string{ "T1", "T2" }) + a.S5(&str) + a.S5(nil) + a = wrap.NewDirectorMyClass(nil) s = a.Adjust(m) if s.Str != `{"first":"second"}` { diff --git a/Examples/test-suite/go_director_inout.i b/Examples/test-suite/go_director_inout.i index b12e5da52..c11b963f5 100644 --- a/Examples/test-suite/go_director_inout.i +++ b/Examples/test-suite/go_director_inout.i @@ -225,6 +225,7 @@ class MyClass { virtual void S2(std::string& s) = 0; virtual void S3(std::string* s) = 0; virtual void S4(const char * const *strarray); + virtual int S5(const std::string* s); }; void MyClass::S1(std::string s) { @@ -239,4 +240,12 @@ void MyClass::CallS4(const char * const *strarray) { this->S4(strarray); } +int MyClass::S5(const std::string* s) { + if (s) { + return (*s)[0]; + } else { + return 0; + } +} + %} diff --git a/Lib/go/std_string.i b/Lib/go/std_string.i index c362f5c5e..3abf04cae 100644 --- a/Lib/go/std_string.i +++ b/Lib/go/std_string.i @@ -93,17 +93,22 @@ class string; %typemap(in) string * (string temp) %{ - temp.assign($input->p, $input->n); - $1 = &temp; + if ($input) { + temp.assign($input->p, $input->n); + $1 = &temp; + } else + $1 = 0; %} %typemap(godirectorout) string * %{ - { + if $input != nil { p := Swig_malloc(len(*$input)) s := (*[1<<30]byte)(unsafe.Pointer(p))[:len(*$input)] copy(s, *$input) $result = (*string)(unsafe.Pointer(&s)) + } else { + $result = nil } %} @@ -125,17 +130,27 @@ class string; %typemap(directorin,fragment="AllocateString") string * (_gostring_ temp) %{ - temp = Swig_AllocateString($1->data(), $1->length()); - $input = &temp; + if ($1) { + temp = Swig_AllocateString($1->data(), $1->length()); + $input = &temp; + } else + $input = 0; %} %typemap(godirectorin,fragment="CopyString") string * %{ *$result = swigCopyString(*$input); %} %typemap(argout,fragment="AllocateString") string * -%{ *$input = Swig_AllocateString($1->data(), $1->length()); %} +%{ + if ($1) + *$input = Swig_AllocateString($1->data(), $1->length()); +%} %typemap(goargout,fragment="CopyString") string * -%{ *$input = swigCopyString(*$1) %} +%{ + if $input != nil { + *$1 = swigCopyString(*$input) + } +%} } diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx index d828b00aa..1692e905a 100644 --- a/Source/Modules/go.cxx +++ b/Source/Modules/go.cxx @@ -3580,11 +3580,162 @@ private: Printv(f_go_wrappers, "}\n\n", NULL); - // Define a method in the C++ director class that the C++ upcall - // function can call. This permits an upcall to a protected - // method. - if (!GetFlag(n, "abstract")) { + // Define a function that uses the Go director type that other + // methods in the Go type can call to get parent methods. + + Printv(f_go_wrappers, "func Director", cn, go_with_over_name, "(swig_p ", cn, NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goType(n, result); + Printv(f_go_wrappers, " ", tm, NULL); + Delete(tm); + } + + Printv(f_go_wrappers, " {\n", NULL); + + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; + String *goout = NULL; + if (SwigType_type(result) != T_VOID) { + ret_type = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + goout = goTypemapLookup("goout", n, "swig_r"); + + bool c_struct_type; + Delete(cgoTypeForGoValue(n, result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + } + + String *call = NewString(""); + + Printv(call, "\t", NULL); + if (SwigType_type(result) != T_VOID) { + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = (", ret_type, ")(", NULL); + } + if (goTypeIsInterface(n, result)) { + wt = goWrapperType(n, result, true); + Printv(call, "(", wt, ")(", NULL); + } + } + + Printv(call, "C.", upcall_wname, "(C.uintptr_t(swig_p.(*", + director_struct_name, ").", go_type_name, ")", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + Printv(call, ", ", NULL); + p = getParm(p); + SwigType *pt = Getattr(p, "type"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *ln = Copy(Getattr(p, "lname")); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", NULL); + bool need_close = false; + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, "getSwigcptr(", NULL); + need_close = true; + } + Printv(f_go_wrappers, ln, NULL); + if (need_close) { + Printv(f_go_wrappers, ")", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + + Delete(ln); + + p = nextParm(p); + } + + Printv(call, ")", NULL); + + if (wt) { + // Close the type conversion to the wrapper type. + Printv(call, ")", NULL); + } + if (SwigType_type(result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(call, ")", NULL); + } + + Printv(call, "\n", NULL); + + Printv(f_go_wrappers, call, NULL); + Delete(call); + + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + + goargout(parms); + + if (SwigType_type(result) != T_VOID) { + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(n, result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + if (ret_type) { + Delete(ret_type); + } + if (wt) { + Delete(wt); + } + + // Define a method in the C++ director class that the C++ + // upcall function can call. This permits an upcall to a + // protected method. + String *upcall_method_name = NewString("_swig_upcall_"); Append(upcall_method_name, name); if (overname) { @@ -3683,157 +3834,6 @@ private: Swig_restore(n); Delete(upcall_method_name); - - // Define a function that uses the Go director type that other - // methods in the Go type can call to get parent methods. - - Printv(f_go_wrappers, "func Director", cn, go_with_over_name, "(p ", cn, NULL); - - p = parms; - for (int i = 0; i < parm_count; ++i) { - p = getParm(p); - Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); - String *tm = goType(p, Getattr(p, "type")); - Printv(f_go_wrappers, tm, NULL); - Delete(tm); - p = nextParm(p); - } - - Printv(f_go_wrappers, ")", NULL); - - if (SwigType_type(result) != T_VOID) { - String *tm = goType(n, result); - Printv(f_go_wrappers, " ", tm, NULL); - Delete(tm); - } - - Printv(f_go_wrappers, " {\n", NULL); - - String *ret_type = NULL; - bool memcpy_ret = false; - String *wt = NULL; - String *goout = NULL; - if (SwigType_type(result) != T_VOID) { - ret_type = goImType(n, result); - Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); - goout = goTypemapLookup("goout", n, "swig_r"); - - bool c_struct_type; - Delete(cgoTypeForGoValue(n, result, &c_struct_type)); - if (c_struct_type) { - memcpy_ret = true; - } - } - - String *call = NewString(""); - - Printv(call, "\t", NULL); - if (SwigType_type(result) != T_VOID) { - if (memcpy_ret) { - Printv(call, "swig_r_p := ", NULL); - } else { - Printv(call, "swig_r = (", ret_type, ")(", NULL); - } - if (goTypeIsInterface(n, result)) { - wt = goWrapperType(n, result, true); - Printv(call, "(", wt, ")(", NULL); - } - } - - Printv(call, "C.", upcall_wname, "(C.uintptr_t(p.(*", - director_struct_name, ").", go_type_name, ")", NULL); - - p = parms; - for (int i = 0; i < parm_count; ++i) { - Printv(call, ", ", NULL); - p = getParm(p); - SwigType *pt = Getattr(p, "type"); - - String *ivar = NewStringf("_swig_i_%d", i); - - String *ln = Copy(Getattr(p, "lname")); - - String *goin = goGetattr(p, "tmap:goin"); - if (goin == NULL) { - Printv(f_go_wrappers, "\t", ivar, " := ", NULL); - bool need_close = false; - if (goTypeIsInterface(p, pt)) { - Printv(f_go_wrappers, "getSwigcptr(", NULL); - need_close = true; - } - Printv(f_go_wrappers, ln, NULL); - if (need_close) { - Printv(f_go_wrappers, ")", NULL); - } - Printv(f_go_wrappers, "\n", NULL); - } else { - String *itm = goImType(p, pt); - Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); - goin = Copy(goin); - Replaceall(goin, "$input", ln); - Replaceall(goin, "$result", ivar); - Printv(f_go_wrappers, goin, "\n", NULL); - Delete(goin); - } - - Setattr(p, "emit:goinput", ivar); - - bool c_struct_type; - String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); - if (c_struct_type) { - Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); - } else { - Printv(call, "C.", ct, "(", ivar, ")", NULL); - } - - Delete(ln); - - p = nextParm(p); - } - - Printv(call, ")", NULL); - - if (wt) { - // Close the type conversion to the wrapper type. - Printv(call, ")", NULL); - } - if (SwigType_type(result) != T_VOID && !memcpy_ret) { - // Close the type conversion of the return value. - Printv(call, ")", NULL); - } - - Printv(call, "\n", NULL); - - Printv(f_go_wrappers, call, NULL); - Delete(call); - - if (memcpy_ret) { - Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); - } - - goargout(parms); - - if (SwigType_type(result) != T_VOID) { - if (goout == NULL) { - Printv(f_go_wrappers, "\treturn swig_r\n", NULL); - } else { - String *tm = goType(n, result); - Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); - Replaceall(goout, "$input", "swig_r"); - Replaceall(goout, "$result", "swig_r_1"); - Printv(f_go_wrappers, goout, "\n", NULL); - Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); - } - } - - Printv(f_go_wrappers, "}\n\n", NULL); - - if (ret_type) { - Delete(ret_type); - } - if (wt) { - Delete(wt); - } } // The Go function which invokes the method. This is called by