]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: strip top-level const qualifier from argument frame struct
authorIan Lance Taylor <iant@golang.org>
Mon, 3 Nov 2025 23:54:39 +0000 (15:54 -0800)
committerGopher Robot <gobot@golang.org>
Fri, 21 Nov 2025 20:40:14 +0000 (12:40 -0800)
Otherwise we can't assign to it.

Fixes #75751

Change-Id: Iba680db672297bca1a1d1a33912b80863da66a08
Reviewed-on: https://go-review.googlesource.com/c/go/+/717342
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/cgo/internal/test/test.go
src/cmd/cgo/out.go

index 9626407d882ef2b4222fbd77339213b2e467d8dc..e83e367174aa4f240bb85e5575aa145a30fb1a8a 100644 (file)
@@ -953,6 +953,12 @@ typedef struct {
 } issue69086struct;
 static int issue690861(issue69086struct* p) { p->b = 1234; return p->c; }
 static int issue690862(unsigned long ul1, unsigned long ul2, unsigned int u, issue69086struct s) { return (int)(s.b); }
+
+char issue75751v = 1;
+char * const issue75751p = &issue75751v;
+#define issue75751m issue75751p
+char * const volatile issue75751p2 = &issue75751v;
+#define issue75751m2 issue75751p2
 */
 import "C"
 
@@ -2396,3 +2402,8 @@ func test69086(t *testing.T) {
                t.Errorf("call: got %d, want 1234", got)
        }
 }
+
+// Issue 75751: no runtime test, just make sure it compiles.
+func test75751() int {
+       return int(*C.issue75751m) + int(*C.issue75751m2)
+}
index 701a8530ffc9840e7f9fca0ed57d577771c895d2..00c9e8c9a3ec61a483486579f26c8b2014472e0c 100644 (file)
@@ -457,6 +457,36 @@ func checkImportSymName(s string) {
 // Also assumes that gc convention is to word-align the
 // input and output parameters.
 func (p *Package) structType(n *Name) (string, int64) {
+       // It's possible for us to see a type with a top-level const here,
+       // which will give us an unusable struct type. See #75751.
+       // The top-level const will always appear as a final qualifier,
+       // constructed by typeConv.loadType in the dwarf.QualType case.
+       // The top-level const is meaningless here and can simply be removed.
+       stripConst := func(s string) string {
+               i := strings.LastIndex(s, "const")
+               if i == -1 {
+                       return s
+               }
+
+               // A top-level const can only be followed by other qualifiers.
+               if r, ok := strings.CutSuffix(s, "const"); ok {
+                       return strings.TrimSpace(r)
+               }
+
+               var nonConst []string
+               for _, f := range strings.Fields(s[i:]) {
+                       switch f {
+                       case "const":
+                       case "restrict", "volatile":
+                               nonConst = append(nonConst, f)
+                       default:
+                               return s
+                       }
+               }
+
+               return strings.TrimSpace(s[:i]) + " " + strings.Join(nonConst, " ")
+       }
+
        var buf strings.Builder
        fmt.Fprint(&buf, "struct {\n")
        off := int64(0)
@@ -468,7 +498,7 @@ func (p *Package) structType(n *Name) (string, int64) {
                }
                c := t.Typedef
                if c == "" {
-                       c = t.C.String()
+                       c = stripConst(t.C.String())
                }
                fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
                off += t.Size
@@ -484,7 +514,7 @@ func (p *Package) structType(n *Name) (string, int64) {
                        fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
                        off += pad
                }
-               fmt.Fprintf(&buf, "\t\t%s r;\n", t.C)
+               fmt.Fprintf(&buf, "\t\t%s r;\n", stripConst(t.C.String()))
                off += t.Size
        }
        if off%p.PtrSize != 0 {