Description
//go:notinheap
is the only current type pragma, and it imposes a lot of complexity and special cases on the compiler and tools. E.g., it's not captured within the go/types or types2 type models, so users wanting to analyze code that uses it have to do a lot of effort to reconstruct this information. The reflect API wasn't updated to reject ChanOf or MapOf for notinheap types. Even the existing compiler typechecker that was extended to natively support //go:notinheap
fails to handle tricky situations: https://play.golang.org/p/hYGrwJx37TN
//go:notinheap
is effectively a language change, but it bypassed review by the usual language spec reviewers because it started out as a runtime-only hack. It was then extended to be used by cmd/cgo and be accessible to user packages (as a necessity of cmd/cgo's design), but again skipped language review.
We already have what are effectively type pragmas in the form of "noCompare" (where embedding a non-comparable, zero-size type makes the enclosing struct non-comparable too) and "noCopy" (where cmd/vet can detect value copies of types that directly contain an element of type "noCopy"). However, they work much more robustly and interoperate with existing tooling better because they rely on struct field embedding, rather than introducing actual type pragmas. I think //go:notinheap
should be modified to work similarly.
I propose the following:
-
Add a new
NotInHeap
type to runtime/internal/sys. Its initial definition would be:type NotInHeap struct { _ nih } //go:notinheap type nih struct{}
-
Disallow all other use of
//go:notinheap
, and maybe eventually get rid of it altogether by turningsys.NotInHeap
into a compiler intrinsic type likeunsafe.Pointer
. -
Change existing runtime types that use
//go:notinheap
to add asys.NotInHeap
-typed field instead. The handful of defined types that are marked//go:notinheap
but aren't already a struct type (i.e., debugLogBuf, checkmarksMap, gcBits) would need to be adjusted to use a struct wrapper. -
Add a new
runtime/cgo.Incomplete
type with the definition:type Incomplete struct { _ sys.NotInHeap }
. Change cmd/cgo to emittype _Ctype_struct_foo cgo.Incomplete
instead of usingstruct{}
with a//go:notinheap
directive. -
Disallow the reintroduction of type pragmas, even for runtime use, without proposal review. (I have no objection to runtime-internal intrinsic types though.)
Incidentally, this is also the approach I took in implementing https://go-review.googlesource.com/c/go/+/308971 as a proof of concept of #19057 (adding intrinsic types to allow adjusting field alignment) for use within the runtime. I think it worked cleanly, and it avoided requiring the introduction of new type pragmas. Instead, it added runtime/internal/align.elemT
as an intrinsic type known to the compiler with special alignment semantics.