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 <thanm@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 0239149..e786aea 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -132,12 +132,11 @@
 //
 // For example, the following string:
 //
-//     `a b:"c d" 'e''f'  "g\""`
+//	`a b:"c d" 'e''f'  "g\""`
 //
 // Would be parsed as:
 //
-//     []string{"a", "b:c d", "ef", `g"`}
-//
+//	[]string{"a", "b:c d", "ef", `g"`}
 func splitQuoted(s string) (r []string, err error) {
 	var args []string
 	arg := make([]rune, len(s))
@@ -1156,13 +1155,19 @@
 
 // checkIndex checks whether arg has the form &a[i], possibly inside
 // type conversions. If so, then in the general case it writes
-//    _cgoIndexNN := a
-//    _cgoNN := &cgoIndexNN[i] // with type conversions, if any
+//
+//	_cgoIndexNN := a
+//	_cgoNN := &cgoIndexNN[i] // with type conversions, if any
+//
 // to sb, and writes
-//    _cgoCheckPointer(_cgoNN, _cgoIndexNN)
+//
+//	_cgoCheckPointer(_cgoNN, _cgoIndexNN)
+//
 // to sbCheck, and returns true. If a is a simple variable or field reference,
 // it writes
-//    _cgoIndexNN := &a
+//
+//	_cgoIndexNN := &a
+//
 // and dereferences the uses of _cgoIndexNN. Taking the address avoids
 // making a copy of an array.
 //
@@ -1210,10 +1215,14 @@
 
 // checkAddr checks whether arg has the form &x, possibly inside type
 // conversions. If so, it writes
-//    _cgoBaseNN := &x
-//    _cgoNN := _cgoBaseNN // with type conversions, if any
+//
+//	_cgoBaseNN := &x
+//	_cgoNN := _cgoBaseNN // with type conversions, if any
+//
 // to sb, and writes
-//    _cgoCheckPointer(_cgoBaseNN, true)
+//
+//	_cgoCheckPointer(_cgoBaseNN, true)
+//
 // to sbCheck, and returns true. This tells _cgoCheckPointer to check
 // just the contents of the pointer being passed, not any other part
 // of the memory allocation. This is run after checkIndex, which looks
@@ -2131,8 +2140,8 @@
 	// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
 	getTypeIDs map[string]bool
 
-	// badStructs contains C structs that should be marked NotInHeap.
-	notInHeapStructs map[string]bool
+	// incompleteStructs contains C structs that should be marked Incomplete.
+	incompleteStructs map[string]bool
 
 	// Predeclared types.
 	bool                                   ast.Expr
@@ -2145,7 +2154,6 @@
 	string                                 ast.Expr
 	goVoid                                 ast.Expr // _Ctype_void, denotes C's void
 	goVoidPtr                              ast.Expr // unsafe.Pointer or *byte
-	goVoidPtrNoHeap                        ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
 
 	ptrSize int64
 	intSize int64
@@ -2169,7 +2177,7 @@
 	c.m = make(map[string]*Type)
 	c.ptrs = make(map[string][]*Type)
 	c.getTypeIDs = make(map[string]bool)
-	c.notInHeapStructs = make(map[string]bool)
+	c.incompleteStructs = make(map[string]bool)
 	c.bool = c.Ident("bool")
 	c.byte = c.Ident("byte")
 	c.int8 = c.Ident("int8")
@@ -2188,7 +2196,6 @@
 	c.void = c.Ident("void")
 	c.string = c.Ident("string")
 	c.goVoid = c.Ident("_Ctype_void")
-	c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
 
 	// Normally cgo translates void* to unsafe.Pointer,
 	// but for historical reasons -godefs uses *byte instead.
@@ -2531,19 +2538,13 @@
 			// other than try to determine a Go representation.
 			tt := *t
 			tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
-			tt.Go = c.Ident("struct{}")
-			if dt.Kind == "struct" {
-				// We don't know what the representation of this struct is, so don't let
-				// anyone allocate one on the Go side. As a side effect of this annotation,
-				// pointers to this type will not be considered pointers in Go. They won't
-				// get writebarrier-ed or adjusted during a stack copy. This should handle
-				// all the cases badPointerTypedef used to handle, but hopefully will
-				// continue to work going forward without any more need for cgo changes.
-				tt.NotInHeap = true
-				// TODO: we should probably do the same for unions. Unions can't live
-				// on the Go heap, right? It currently doesn't work for unions because
-				// they are defined as a type alias for struct{}, not a defined type.
-			}
+			// We don't know what the representation of this struct is, so don't let
+			// anyone allocate one on the Go side. As a side effect of this annotation,
+			// pointers to this type will not be considered pointers in Go. They won't
+			// get writebarrier-ed or adjusted during a stack copy. This should handle
+			// all the cases badPointerTypedef used to handle, but hopefully will
+			// continue to work going forward without any more need for cgo changes.
+			tt.Go = c.Ident("_cgopackage.Incomplete")
 			typedef[name.Name] = &tt
 			break
 		}
@@ -2569,7 +2570,9 @@
 				tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
 			}
 			tt.Go = g
-			tt.NotInHeap = c.notInHeapStructs[tag]
+			if c.incompleteStructs[tag] {
+				tt.Go = c.Ident("_cgopackage.Incomplete")
+			}
 			typedef[name.Name] = &tt
 		}
 
@@ -2614,9 +2617,9 @@
 			}
 		}
 		if c.badVoidPointerTypedef(dt) {
-			// Treat this typedef as a pointer to a NotInHeap void.
+			// Treat this typedef as a pointer to a _cgopackage.Incomplete.
 			s := *sub
-			s.Go = c.goVoidPtrNoHeap
+			s.Go = c.Ident("*_cgopackage.Incomplete")
 			sub = &s
 			// Make sure we update any previously computed type.
 			if oldType := typedef[name.Name]; oldType != nil {
@@ -2624,22 +2627,21 @@
 			}
 		}
 		// Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
-		// typedefs that should be marked NotInHeap.
+		// typedefs that should be marked Incomplete.
 		if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
 			if strct, ok := ptr.Type.(*dwarf.StructType); ok {
 				if c.badStructPointerTypedef(dt.Name, strct) {
-					c.notInHeapStructs[strct.StructName] = true
+					c.incompleteStructs[strct.StructName] = true
 					// Make sure we update any previously computed type.
 					name := "_Ctype_struct_" + strct.StructName
 					if oldType := typedef[name]; oldType != nil {
-						oldType.NotInHeap = true
+						oldType.Go = c.Ident("_cgopackage.Incomplete")
 					}
 				}
 			}
 		}
 		t.Go = name
 		t.BadPointer = sub.BadPointer
-		t.NotInHeap = sub.NotInHeap
 		if unionWithPointer[sub.Go] {
 			unionWithPointer[t.Go] = true
 		}
@@ -2650,7 +2652,6 @@
 			tt := *t
 			tt.Go = sub.Go
 			tt.BadPointer = sub.BadPointer
-			tt.NotInHeap = sub.NotInHeap
 			typedef[name.Name] = &tt
 		}
 
@@ -3174,7 +3175,7 @@
 // non-pointers in this type.
 // TODO: Currently our best solution is to find these manually and list them as
 // they come up. A better solution is desired.
-// Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file.
+// Note: DEPRECATED. There is now a better solution. Search for _cgopackage.Incomplete in this file.
 func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
 	if c.badCFType(dt) {
 		return true
@@ -3188,7 +3189,7 @@
 	return false
 }
 
-// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be NotInHeap.
+// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be _cgopackage.Incomplete.
 func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
 	// Match the Windows HANDLE type (#42018).
 	if goos != "windows" || dt.Name != "HANDLE" {
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 58477e4..186aef0 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -153,7 +153,6 @@
 	EnumValues map[string]int64
 	Typedef    string
 	BadPointer bool // this pointer type should be represented as a uintptr (deprecated)
-	NotInHeap  bool // this type should have a go:notinheap annotation
 }
 
 // A FuncType collects information about a function type in both the C and Go worlds.
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 8d1eb5b..9ed88b8 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -85,11 +85,14 @@
 	fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
 	fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
 	fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
-	if !*gccgo && *importRuntimeCgo {
-		fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
-	}
 	if *importSyscall {
 		fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+	}
+	if *importRuntimeCgo {
+		fmt.Fprintf(fgo2, "import _cgopackage \"runtime/cgo\"\n\n")
+		fmt.Fprintf(fgo2, "type _ _cgopackage.Incomplete\n") // prevent import-not-used error
+	}
+	if *importSyscall {
 		fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
 	}
 	fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
@@ -113,9 +116,6 @@
 	sort.Strings(typedefNames)
 	for _, name := range typedefNames {
 		def := typedef[name]
-		if def.NotInHeap {
-			fmt.Fprintf(fgo2, "//go:notinheap\n")
-		}
 		fmt.Fprintf(fgo2, "type %s ", name)
 		// We don't have source info for these types, so write them out without source info.
 		// Otherwise types would look like:
@@ -140,7 +140,6 @@
 		fmt.Fprintf(fgo2, "%s", buf.Bytes())
 		fmt.Fprintf(fgo2, "\n\n")
 	}
-	fmt.Fprintf(fgo2, "//go:notinheap\ntype _Ctype_void_notinheap struct{}\n\n")
 	if *gccgo {
 		fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
 	} else {
diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go
index 44bd61c..9c5c0a1 100644
--- a/libgo/go/cmd/go/internal/load/pkg.go
+++ b/libgo/go/cmd/go/internal/load/pkg.go
@@ -1818,7 +1818,7 @@
 		if p.UsesCgo() {
 			addImport("unsafe", true)
 		}
-		if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
+		if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) {
 			addImport("runtime/cgo", true)
 		}
 		if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
@@ -1828,9 +1828,7 @@
 		// SWIG adds imports of some standard packages.
 		if p.UsesSwig() {
 			addImport("unsafe", true)
-			if cfg.BuildContext.Compiler != "gccgo" {
-				addImport("runtime/cgo", true)
-			}
+			addImport("runtime/cgo", true)
 			addImport("syscall", true)
 			addImport("sync", true)
 
@@ -2455,7 +2453,7 @@
 	deps := []string{"runtime"}
 
 	// External linking mode forces an import of runtime/cgo.
-	if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" {
+	if externalLinkingForced(p) {
 		deps = append(deps, "runtime/cgo")
 	}
 	// On ARM with GOARM=5, it forces an import of math, for soft floating point.
diff --git a/libgo/go/runtime/cgo/cgo.go b/libgo/go/runtime/cgo/cgo.go
new file mode 100644
index 0000000..5921435
--- /dev/null
+++ b/libgo/go/runtime/cgo/cgo.go
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package cgo contains runtime support for code generated
+by the cgo tool.  See the documentation for the cgo command
+for details on using cgo.
+*/
+package cgo
+
+// Incomplete is used specifically for the semantics of incomplete C types.
+//
+//go:notinheap
+type Incomplete struct {
+	//	_ sys.NotInHeap
+	_ struct{ _ struct{} }
+}