diff --git a/CHANGES.current b/CHANGES.current
index 2f48aa2b6..5b6ff9445 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.4.0 (in progress)
===========================
+2025-06-27: ianlancetaylor
+ Use unsafe for Go strings rather than byte arrays.
+ Update minimum Go supported version to 1.20.
+
2025-06-23: jschueller
#3184 #3196 [Python] Support multi-phase module initialization.
diff --git a/Doc/Manual/Go.html b/Doc/Manual/Go.html
index 13c657799..6b063584c 100644
--- a/Doc/Manual/Go.html
+++ b/Doc/Manual/Go.html
@@ -73,7 +73,7 @@ code. SWIG fills this gap.
There are (at least) two different Go compilers. The first is the gc compiler
of the Go distribution, normally
invoked via the go tool.
-SWIG supports the gc compiler version 1.2 or later.
+SWIG supports the gc compiler version 1.20 or later.
The second Go compiler is the
gccgo compiler, which is a frontend to the GCC compiler suite.
The interface to C/C++ code is completely different for the two Go compilers.
diff --git a/Examples/Makefile.in b/Examples/Makefile.in
index dec9b1609..98b6d6c85 100644
--- a/Examples/Makefile.in
+++ b/Examples/Makefile.in
@@ -434,7 +434,7 @@ $(GOPATHPARENTDIR)/go.mod:
@mkdir $(GOPATHDIR) 2>/dev/null || true
echo "module swigtests" > $(GOPATHDIR)/go.mod
echo "" >> $(GOPATHDIR)/go.mod
- echo "go 1.12" >> $(GOPATHDIR)/go.mod
+ echo "go 1.20" >> $(GOPATHDIR)/go.mod
mv -f $(GOPATHDIR)/go.mod $(GOPATHPARENTDIR)/go.mod
go: $(SRCDIR_SRCS) $(GOPATHPARENTDIR)/go.mod
diff --git a/Lib/go/cdata.i b/Lib/go/cdata.i
index 77b08ec7a..6905bd73b 100644
--- a/Lib/go/cdata.i
+++ b/Lib/go/cdata.i
@@ -46,7 +46,7 @@ struct swigcdata {
$result = nil
} else {
b := make([]byte, p.size)
- a := (*[0x7fffffff]byte)(unsafe.Pointer(p.data))[:p.size]
+ a := unsafe.Slice((*byte)(unsafe.Pointer(p.data)), p.size)
copy(b, a)
Swig_free(p.data)
Swig_free(uintptr(unsafe.Pointer(p)))
diff --git a/Lib/go/go.swg b/Lib/go/go.swg
index 8f5bb4fcd..ede17e7da 100644
--- a/Lib/go/go.swg
+++ b/Lib/go/go.swg
@@ -485,10 +485,10 @@ rvrdeleter.reset($1); %}
%{
{
p := Swig_malloc(len($input) + 1)
- s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input) + 1]
+ s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input) + 1)
copy(s, $input)
s[len($input)] = 0
- $result = *(*string)(unsafe.Pointer(&s))
+ $result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input) + 1)
}
%}
diff --git a/Lib/go/gostring.swg b/Lib/go/gostring.swg
index 44cbbb8ee..001708113 100644
--- a/Lib/go/gostring.swg
+++ b/Lib/go/gostring.swg
@@ -22,7 +22,7 @@ static _gostring_ Swig_AllocateString(const char *p, size_t l) {
type swig_gostring struct { p uintptr; n int }
func swigCopyString(s string) string {
p := *(*swig_gostring)(unsafe.Pointer(&s))
- r := string((*[0x7fffffff]byte)(unsafe.Pointer(p.p))[:p.n])
+ r := string(unsafe.Slice((*byte)(unsafe.Pointer(p.p)), p.n))
Swig_free(p.p)
return r
}
diff --git a/Lib/go/std_string.i b/Lib/go/std_string.i
index 35b4a5e46..f6af8e14f 100644
--- a/Lib/go/std_string.i
+++ b/Lib/go/std_string.i
@@ -28,9 +28,9 @@ class string;
%{
{
p := Swig_malloc(len($input))
- s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input)]
+ s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input))
copy(s, $input)
- $result = *(*string)(unsafe.Pointer(&s))
+ $result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input))
}
%}
@@ -65,9 +65,9 @@ class string;
%{
{
p := Swig_malloc(len($input))
- s := (*[1<<30]byte)(unsafe.Pointer(p))[:len($input)]
+ s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len($input))
copy(s, $input)
- $result = *(*string)(unsafe.Pointer(&s))
+ $result = unsafe.String((*byte)(unsafe.Pointer(p)), len($input))
}
%}
@@ -110,7 +110,7 @@ class string;
%{
if $input != nil {
p := Swig_malloc(len(*$input))
- s := (*[1<<30]byte)(unsafe.Pointer(p))[:len(*$input)]
+ s := unsafe.Slice((*byte)(unsafe.Pointer(p)), len(*$input))
copy(s, *$input)
$result = (*string)(unsafe.Pointer(&s))
} else {