[Go] #2245 Handle NULL pointers for string* conversions.

Rearrange generation of director methods and rename
receiver argument from p to swig_p.

Fixes #2245
This commit is contained in:
Ian Lance Taylor 2022-07-05 17:00:21 -07:00
commit 87cbf8c341
5 changed files with 194 additions and 162 deletions

View file

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

View file

@ -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"}` {

View file

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

View file

@ -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)
}
%}
}

View file

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