Skip to content

Commit 42efec8

Browse files
cmd/cgo: add and use runtime/cgo.Incomplete instead of //go:notinheap
This ports https://go.dev/cl/421879 to libgo. This is a quick port to update gofrontend to work with the version of cgo in gc mainline. A more complete port will follow, changing the gc version of cmd/cgo to choose an approach based on feature testing the gccgo in use. Updates golang/go#46731 Change-Id: I61d1f97781ac1aeb5f8a51ddeb1db378d8c97f95 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/432338 Reviewed-by: Than McIntosh <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 6543b7f commit 42efec8

File tree

5 files changed

+66
-51
lines changed

5 files changed

+66
-51
lines changed

libgo/go/cmd/cgo/gcc.go

+39-38
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,11 @@ func (p *Package) addToFlag(flag string, args []string) {
132132
//
133133
// For example, the following string:
134134
//
135-
// `a b:"c d" 'e''f' "g\""`
135+
// `a b:"c d" 'e''f' "g\""`
136136
//
137137
// Would be parsed as:
138138
//
139-
// []string{"a", "b:c d", "ef", `g"`}
140-
//
139+
// []string{"a", "b:c d", "ef", `g"`}
141140
func splitQuoted(s string) (r []string, err error) {
142141
var args []string
143142
arg := make([]rune, len(s))
@@ -1156,13 +1155,19 @@ func (p *Package) mangle(f *File, arg *ast.Expr, addPosition bool) (ast.Expr, bo
11561155

11571156
// checkIndex checks whether arg has the form &a[i], possibly inside
11581157
// type conversions. If so, then in the general case it writes
1159-
// _cgoIndexNN := a
1160-
// _cgoNN := &cgoIndexNN[i] // with type conversions, if any
1158+
//
1159+
// _cgoIndexNN := a
1160+
// _cgoNN := &cgoIndexNN[i] // with type conversions, if any
1161+
//
11611162
// to sb, and writes
1162-
// _cgoCheckPointer(_cgoNN, _cgoIndexNN)
1163+
//
1164+
// _cgoCheckPointer(_cgoNN, _cgoIndexNN)
1165+
//
11631166
// to sbCheck, and returns true. If a is a simple variable or field reference,
11641167
// it writes
1165-
// _cgoIndexNN := &a
1168+
//
1169+
// _cgoIndexNN := &a
1170+
//
11661171
// and dereferences the uses of _cgoIndexNN. Taking the address avoids
11671172
// making a copy of an array.
11681173
//
@@ -1210,10 +1215,14 @@ func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) boo
12101215

12111216
// checkAddr checks whether arg has the form &x, possibly inside type
12121217
// conversions. If so, it writes
1213-
// _cgoBaseNN := &x
1214-
// _cgoNN := _cgoBaseNN // with type conversions, if any
1218+
//
1219+
// _cgoBaseNN := &x
1220+
// _cgoNN := _cgoBaseNN // with type conversions, if any
1221+
//
12151222
// to sb, and writes
1216-
// _cgoCheckPointer(_cgoBaseNN, true)
1223+
//
1224+
// _cgoCheckPointer(_cgoBaseNN, true)
1225+
//
12171226
// to sbCheck, and returns true. This tells _cgoCheckPointer to check
12181227
// just the contents of the pointer being passed, not any other part
12191228
// of the memory allocation. This is run after checkIndex, which looks
@@ -2131,8 +2140,8 @@ type typeConv struct {
21312140
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
21322141
getTypeIDs map[string]bool
21332142

2134-
// badStructs contains C structs that should be marked NotInHeap.
2135-
notInHeapStructs map[string]bool
2143+
// incompleteStructs contains C structs that should be marked Incomplete.
2144+
incompleteStructs map[string]bool
21362145

21372146
// Predeclared types.
21382147
bool ast.Expr
@@ -2145,7 +2154,6 @@ type typeConv struct {
21452154
string ast.Expr
21462155
goVoid ast.Expr // _Ctype_void, denotes C's void
21472156
goVoidPtr ast.Expr // unsafe.Pointer or *byte
2148-
goVoidPtrNoHeap ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
21492157

21502158
ptrSize int64
21512159
intSize int64
@@ -2169,7 +2177,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
21692177
c.m = make(map[string]*Type)
21702178
c.ptrs = make(map[string][]*Type)
21712179
c.getTypeIDs = make(map[string]bool)
2172-
c.notInHeapStructs = make(map[string]bool)
2180+
c.incompleteStructs = make(map[string]bool)
21732181
c.bool = c.Ident("bool")
21742182
c.byte = c.Ident("byte")
21752183
c.int8 = c.Ident("int8")
@@ -2188,7 +2196,6 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
21882196
c.void = c.Ident("void")
21892197
c.string = c.Ident("string")
21902198
c.goVoid = c.Ident("_Ctype_void")
2191-
c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
21922199

21932200
// Normally cgo translates void* to unsafe.Pointer,
21942201
// but for historical reasons -godefs uses *byte instead.
@@ -2531,19 +2538,13 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
25312538
// other than try to determine a Go representation.
25322539
tt := *t
25332540
tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
2534-
tt.Go = c.Ident("struct{}")
2535-
if dt.Kind == "struct" {
2536-
// We don't know what the representation of this struct is, so don't let
2537-
// anyone allocate one on the Go side. As a side effect of this annotation,
2538-
// pointers to this type will not be considered pointers in Go. They won't
2539-
// get writebarrier-ed or adjusted during a stack copy. This should handle
2540-
// all the cases badPointerTypedef used to handle, but hopefully will
2541-
// continue to work going forward without any more need for cgo changes.
2542-
tt.NotInHeap = true
2543-
// TODO: we should probably do the same for unions. Unions can't live
2544-
// on the Go heap, right? It currently doesn't work for unions because
2545-
// they are defined as a type alias for struct{}, not a defined type.
2546-
}
2541+
// We don't know what the representation of this struct is, so don't let
2542+
// anyone allocate one on the Go side. As a side effect of this annotation,
2543+
// pointers to this type will not be considered pointers in Go. They won't
2544+
// get writebarrier-ed or adjusted during a stack copy. This should handle
2545+
// all the cases badPointerTypedef used to handle, but hopefully will
2546+
// continue to work going forward without any more need for cgo changes.
2547+
tt.Go = c.Ident("_cgopackage.Incomplete")
25472548
typedef[name.Name] = &tt
25482549
break
25492550
}
@@ -2569,7 +2570,9 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
25692570
tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
25702571
}
25712572
tt.Go = g
2572-
tt.NotInHeap = c.notInHeapStructs[tag]
2573+
if c.incompleteStructs[tag] {
2574+
tt.Go = c.Ident("_cgopackage.Incomplete")
2575+
}
25732576
typedef[name.Name] = &tt
25742577
}
25752578

@@ -2614,32 +2617,31 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
26142617
}
26152618
}
26162619
if c.badVoidPointerTypedef(dt) {
2617-
// Treat this typedef as a pointer to a NotInHeap void.
2620+
// Treat this typedef as a pointer to a _cgopackage.Incomplete.
26182621
s := *sub
2619-
s.Go = c.goVoidPtrNoHeap
2622+
s.Go = c.Ident("*_cgopackage.Incomplete")
26202623
sub = &s
26212624
// Make sure we update any previously computed type.
26222625
if oldType := typedef[name.Name]; oldType != nil {
26232626
oldType.Go = sub.Go
26242627
}
26252628
}
26262629
// Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
2627-
// typedefs that should be marked NotInHeap.
2630+
// typedefs that should be marked Incomplete.
26282631
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
26292632
if strct, ok := ptr.Type.(*dwarf.StructType); ok {
26302633
if c.badStructPointerTypedef(dt.Name, strct) {
2631-
c.notInHeapStructs[strct.StructName] = true
2634+
c.incompleteStructs[strct.StructName] = true
26322635
// Make sure we update any previously computed type.
26332636
name := "_Ctype_struct_" + strct.StructName
26342637
if oldType := typedef[name]; oldType != nil {
2635-
oldType.NotInHeap = true
2638+
oldType.Go = c.Ident("_cgopackage.Incomplete")
26362639
}
26372640
}
26382641
}
26392642
}
26402643
t.Go = name
26412644
t.BadPointer = sub.BadPointer
2642-
t.NotInHeap = sub.NotInHeap
26432645
if unionWithPointer[sub.Go] {
26442646
unionWithPointer[t.Go] = true
26452647
}
@@ -2650,7 +2652,6 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
26502652
tt := *t
26512653
tt.Go = sub.Go
26522654
tt.BadPointer = sub.BadPointer
2653-
tt.NotInHeap = sub.NotInHeap
26542655
typedef[name.Name] = &tt
26552656
}
26562657

@@ -3174,7 +3175,7 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
31743175
// non-pointers in this type.
31753176
// TODO: Currently our best solution is to find these manually and list them as
31763177
// they come up. A better solution is desired.
3177-
// Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file.
3178+
// Note: DEPRECATED. There is now a better solution. Search for _cgopackage.Incomplete in this file.
31783179
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
31793180
if c.badCFType(dt) {
31803181
return true
@@ -3188,7 +3189,7 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
31883189
return false
31893190
}
31903191

3191-
// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be NotInHeap.
3192+
// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be _cgopackage.Incomplete.
31923193
func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
31933194
// Match the Windows HANDLE type (#42018).
31943195
if goos != "windows" || dt.Name != "HANDLE" {

libgo/go/cmd/cgo/main.go

-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ type Type struct {
153153
EnumValues map[string]int64
154154
Typedef string
155155
BadPointer bool // this pointer type should be represented as a uintptr (deprecated)
156-
NotInHeap bool // this type should have a go:notinheap annotation
157156
}
158157

159158
// A FuncType collects information about a function type in both the C and Go worlds.

libgo/go/cmd/cgo/out.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,14 @@ func (p *Package) writeDefs() {
8585
fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
8686
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
8787
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
88-
if !*gccgo && *importRuntimeCgo {
89-
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
90-
}
9188
if *importSyscall {
9289
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
90+
}
91+
if *importRuntimeCgo {
92+
fmt.Fprintf(fgo2, "import _cgopackage \"runtime/cgo\"\n\n")
93+
fmt.Fprintf(fgo2, "type _ _cgopackage.Incomplete\n") // prevent import-not-used error
94+
}
95+
if *importSyscall {
9396
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
9497
}
9598
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
@@ -113,9 +116,6 @@ func (p *Package) writeDefs() {
113116
sort.Strings(typedefNames)
114117
for _, name := range typedefNames {
115118
def := typedef[name]
116-
if def.NotInHeap {
117-
fmt.Fprintf(fgo2, "//go:notinheap\n")
118-
}
119119
fmt.Fprintf(fgo2, "type %s ", name)
120120
// We don't have source info for these types, so write them out without source info.
121121
// Otherwise types would look like:
@@ -140,7 +140,6 @@ func (p *Package) writeDefs() {
140140
fmt.Fprintf(fgo2, "%s", buf.Bytes())
141141
fmt.Fprintf(fgo2, "\n\n")
142142
}
143-
fmt.Fprintf(fgo2, "//go:notinheap\ntype _Ctype_void_notinheap struct{}\n\n")
144143
if *gccgo {
145144
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
146145
} else {

libgo/go/cmd/go/internal/load/pkg.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
18181818
if p.UsesCgo() {
18191819
addImport("unsafe", true)
18201820
}
1821-
if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
1821+
if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) {
18221822
addImport("runtime/cgo", true)
18231823
}
18241824
if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
@@ -1828,9 +1828,7 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
18281828
// SWIG adds imports of some standard packages.
18291829
if p.UsesSwig() {
18301830
addImport("unsafe", true)
1831-
if cfg.BuildContext.Compiler != "gccgo" {
1832-
addImport("runtime/cgo", true)
1833-
}
1831+
addImport("runtime/cgo", true)
18341832
addImport("syscall", true)
18351833
addImport("sync", true)
18361834

@@ -2455,7 +2453,7 @@ func LinkerDeps(p *Package) []string {
24552453
deps := []string{"runtime"}
24562454

24572455
// External linking mode forces an import of runtime/cgo.
2458-
if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" {
2456+
if externalLinkingForced(p) {
24592457
deps = append(deps, "runtime/cgo")
24602458
}
24612459
// On ARM with GOARM=5, it forces an import of math, for soft floating point.

libgo/go/runtime/cgo/cgo.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2010 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
/*
6+
Package cgo contains runtime support for code generated
7+
by the cgo tool. See the documentation for the cgo command
8+
for details on using cgo.
9+
*/
10+
package cgo
11+
12+
// Incomplete is used specifically for the semantics of incomplete C types.
13+
//
14+
//go:notinheap
15+
type Incomplete struct {
16+
// _ sys.NotInHeap
17+
_ struct{ _ struct{} }
18+
}

0 commit comments

Comments
 (0)