structs: add HostLayout "directive" type
Closed this issue · 53 comments
Proposal Details
Abstract
This proposes a new package for zero-sized types whose presence in a structure’s list of fields would control how the compiler lays out those fields, for the purpose of allowing programmers to indicate which structures are interchanged with the host platform and to request a host-compatible layout for those structures.
Background
While the Go language specifies very little about struct layout, in practice the Go implementation is tightly constrained to follow platform layout and alignment rules because of the few cases where a struct is interchanged with a platform API (and where this is not true it creates the possibility of incompatibility, for example, ppc64le, where the platform alignment for float64 fields is different from Go's default). This forces tradeoffs or potential problems on platforms whose constraints differ from common-case on other platforms (that is, what the Go compiler has adopted as its default) and prevents field reordering optimizations that can save memory and improve garbage collection performance.
Proposal
To address this, we propose a family of zero-sized types for struct fields to signal differences in layout or alignment where that matters. The change in the compiler’s behavior should be invisible to pure Go programs that do not use unsafe or interact with the host platform. The goal of the proposal is that programmers be able to ensure that data exchanged with the host platform have a host-compatible layout, both now, and in the face of future layout optimizations.
Subject to discussion, the proposal is this package and (for now) this one type:
package structlayout
// Platform, as a field type, signals that the size, alignment,
// and order of fields conform to requirements of the GOOS-GOARCH
// target platform and may not match the Go compiler’s defaults.
type Platform struct {}
After reflecting on the discussion below, I would modify this to:
package structs
// HostLayout, as a field type, signals that the size, alignment,
// and order of fields conform to requirements of the host
// platform and may not match the Go compiler’s defaults.
type HostLayout struct {}
the rationale for the name change is that structs
is one word, and parallels strings
, bytes
, and slices
, and is generic enough to include other (future) tags specifying "nocopy" or alignment. Furthermore, such type-modifying tags only work within structures; the package name strongly hints at this.
Rationale
One platform, WASM, has system interfaces that align 64-bit types to more than register size and another, ppc64le, has the possibility of non-Go interfaces that align some 64-bit types to less than register size, and both of these are contrary to the rules that Go normally follows (on ppc64le, we have handled this problem using luck). Signaling these constraints explicitly will help compatibility with these two platforms, preserve/allow implementation flexibility, perhaps make it easier to write checking tools, and perhaps (once types passed to all non-Go calls are properly tagged) allow the Go compiler to reorder structures to use less memory and save GC time by shuffling pointers as early as possible in untagged structures. This optimization is desirable because it automates something humans currently spend time on and don't always get right, and sometimes forces programmers to make compromises between most-readable code and best performance.
The most important part of this proposal is that unless someone is writing code that interacts with the platform, they do not need to know about this. If they are writing cgo, these signal types will be inserted for them.
The compiler will know the meaning of these types and modify struct alignment and layouts accordingly. It’s not clear to me whether Platform
is adequate to capture all the cases of non-Go code, but for the current use cases (platform interfaces across all the various platforms, and cgo -- as far as I know “platform” describes their needs) it appears that it is.
Why signal types versus //go:platform
?
It is a better match for the Go type system if changes in types are expressed in the type system itself. Use of field signal types meets this requirement, since the Go type of a struct depends on the fields of the struct, even if they have zero width.
Why just one platform
tag instead of finer control?
In practice, the use case is platform compatibility, and platform
is a concept that the compiler can translate to the appropriate ARCH-OS combination without demanding that the user know the details, and those details also might not be portable across platforms even when the C type declarations are the same.
In the future, we could consider adding signal types for CacheAlign
, AtomicAlign
, or Packed
but I would not include those at first because I'm not that sure we need them, we might argue about definitions, and their implementation (for Packed
, at least) would be somewhat more costly. A non-layout signal type that might work well is “NoCopy” to indicate to vet that a type should not be copied once it has a non-zero value (this is currently implemented by vet knowing that certain types are “special”).
Related: “proposal: spec: define/imply memory layout of tagged struct fields #10014”. This was a very similar proposal, approaching the problem from a slightly different direction, but did not address the issue of "the platform does not match Go's defaults". The new proposal here is more concrete in “how”, includes tweaking alignments to conform to platform constraints, but does not expect someone using the platform tag to know precisely what rules a particular platform uses.
Related: “proposal: runtime: add AlignedN types that can be used to increase alignment #19057”. This was a proposal for a family of types for specifying specific alignments, perhaps of specific fields. That proposal had additional use cases -- specifying higher alignment for various fields -- but also did not address the problem of reduced platform alignment (e.g., ppc64le float64) and its application to specific platform interfaces would require that programmers know the details of that platform’s layout rules (instead of the Go compiler/runtime knowing those details once).
Related: “proposal: cmd/compile: make 64-bit fields be 64-bit aligned on 32-bit systems, add //go:packed directive on structs #36606”. This proposal took the opposite approach -- 64-bit atomics require 64-bit alignment on 32-bit processors, therefore Go should change its default layout, rather than signaling specific types that needed this alignment. It also included a secondary proposal for “packed” types that had a far more annoying implementation burden (how is the pointer addressed in a “packed” struct {uint8; *int}
? How does the GC find this pointer?)
Compatibility
Working old code will continue to work properly.
Implementation
Besides the proposed package and type, cmd/compile/internal/types/size.go
will need adjusting to follow the signal types. It already contains special case code for sync/atomic/align64
, so this is not outlandish.
Open issues
The names. For example, “structlayout”, versus “typelayout”? If we decide that this is a good place for 0-width signal types, some of them (NoCopy
) aren’t about type layout which means whatever-layout isn’t quite right.
The names. For example, “structlayout”, versus “typelayout”? If we decide that this is a good place for 0-width signal types, some of them (
NoCopy
) aren’t about type layout which means whatever-layout isn’t quite right.
How about typetag
, e.g. typetag.Platform
and typetag.NoCopy
?
Working old code will continue to work properly.
Will layout changes be guarded behind the module's Go version? I would find that important for the unsafe
case.
Will layout changes be guarded behind the module's Go version? I would find that important for the unsafe case.
This proposal is just part 1, adding the structlayout.Platform
type and implementing its semantics. That is completely backwards-compatible, if you never see that type everything works as before.
Part 2, actually changing the layout of unadorned structs, is not part of this proposal. Of course, this proposal has less motivation if part 2 never happens.
Being part of the type system is a bit weird. Can i throw it in in a interface{}? What happens when i take a pointer to it and it's set to nil. Can i make it generic with type parameters?
@nemith All of those will work fine. This proposal just changes the layout of the fields within a struct. Field layout is already fully described by the reflect.Type
value associated with the type. Nothing else cares.
@nemith Part of the reason for putting it into the type system is so that all the other Go tools understand it, from the point-of-view of type comparison, identity, etc.
If/when additional signal types get added, what are the semantics of including more than one in the same struct? Will it be required that all signal types have orthogonal semantics, will it be a compile time error if they are incompatible? What if they are only incompatible on one platform/OS pair, would there be a vet check to alert someone that doesn't explicitly try that combination to the potential issue?
I see no reason to require orthogonal semantics ("PlatformLayout" overlaps with "DeclaredLayout", which is not yet proposed but I can imagine it) but I do think that incompatible combinations should be diagnosed at compile time. And looking at a plausible interaction with alignment specification (the other/next layout tag I expect to someday see) I can construct plausible examples that would use both.
I think for this particular tag it would be reasonable to require that it precede any other field that has non-zero size.
My goal is to have as few of these tags as possible, motivated by real problems, so hopefully there will not be many combinations that apply, I think it is fine for the compiler to reject any combinations that are problematic. Even one of these tags should be a niche case; two should be niche-squared.
HOWEVER:
This might get messy for special C-hardware-specific types, for example, those used to talk about xmm and ymm registers, that currently have no Go equivalent. There are several approaches to that problem and I am not sure which is best; the existence/names of the very-wide data types is platform-dependent for C compilers, but Go could decide to just generally support 128 and 256-bit integers. Or, we could add per-field type tags for alignment that would precede 128-bit or 256-bit fields. So, something like:
type Ymms struct {
_ typetag.PlatformLayout
Inactive bool
Reg [32]uint256 // These are aligned to a platform-appropriate boundary
}
or
type YmmPart uint64
type Ymms struct {
_ typetag.PlatformLayout
Inactive bool
_ typetag.Align256 // I hope the right alignment is 32-bytes / 256 bits.
Reg [32][4]YmmPart
}
(I added the boolean field just to make it clear that the hypothetical Align256
tag precedes a particular field.)
I prefer the choice where the programmer doesn't need to go read documentation to figure out what the C compiler is doing. On the other hand, after quickly checking what the internet to see what the YMM alignment rules are (and discovering a mess with annoying special cases), I can understand needing to be able to specify a platform order yet also be very picky about the alignment. Because of that, I think that specifying both platform layout and specific (increased) alignment for certain fields should be allowed. Specifying reduced alignment is probably a compile-time error, certainly taking the address of a field with reduced alignment is a compile-time error.
(Why is taking the address of a reduced-alignment field a likely error? The compiler would prefer to use the fast, assume-that-integers-are-aligned, instructions for dereferencing a *int64
, and most people want the compiler to do that because it is faster. Taking the address of an unaligned field breaks that assumption.)
I am not sure if this is right for a vet check or not; vet would need to know a lot about different architecture and OS combinations and their C compilers. A different and slightly interesting question is what should happen if a struct tagged with "platform" layout contains a type that is inherently Go-oriented, like slice or map, or one for which Go has its own alignment assumptions. My inclination is to say that right now vet isn't checking any of this; platform interchange types are already a niche, and weird combinations of type tags (that don't exist yet) and/or Go types is a hypothetical niche of that niche.
@mvdan proposed improved naming, included at the top for anyone coming upon this later and not wanting to slog through comments:
After reflecting on the discussion below, I would modify this to:
package structs
// PlatformLayout, as a field type, signals that the size, alignment,
// and order of fields conform to requirements of the GOOS-GOARCH
// target platform and may not match the Go compiler’s defaults.
type PlatformLayout struct {}
the rationale for the name change is that structs
is one word, and parallels strings
, bytes
, and slices
, and is generic enough to include other (future) tags specifying "nocopy" or alignment. Furthermore, such type-modifying tags only work within structures; the package name strongly hints at this.
Platform is a bit odd since Go is a platform too, and "the GOOS-GOARCH target platform" sounds like Go too.
What about structs.HostLayout, and don't mention GOOS-GOARCH in the docs?
(For the record, the main need for this is to write structs that match Windows and WASM, not Cgo.
Cgo can always do something magical and unexposed.)
Would this also affect the alignment of the struct on the stack?
@ydnar - it depends. On some architectures the stack is not very aligned, and so extra-aligned data is heap-allocated instead. Otherwise, yes, probably.
And I am fine with HostLayout
, will edit the top proposal to reflect this.
This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group
Have all remaining concerns about this proposal been addressed?
The proposal is to add
package structs
type HostLayout struct{}
that can be added as a field named _
in a struct. This would have no significant effect in most tools, but a compiler could use it as a hint about laying out the struct. Of course there is an effect for type equality, since a struct with one of these fields is different from a struct without, but that’s exactly what we want if the compiler is using it to hint a different layout.
Would like to additionally require that this directive-typed field must appear before any field with greater-than-zero size, if that's okay? (This should not be requirement for some imagined other directives, e.g., explicit next-field alignment.)
What advantage do we get from imposing such a requirement?
Simplifies the implementation ever-so-slightly (avoids a pre-pass over structure fields), also makes its use more uniform, and I don't see much harm in the restriction (which could be relaxed later if I turn out to be wrong in "not much harm").
My take on it is that the advantages we get from the restriction aren't worth the cost of complicating the spec by adding the restriction.
Would the field be zero sized if it's the last _ field in a struct?
Change https://go.dev/cl/578355 mentions this issue: cmd/compile: layout changes for wasm32, structs.HostLayout
@ydnar _ fields can have width. A zero-width (field) type is either an array of zero elements, a struct of zero fields, or a struct/array built entirely of zero width types.
I’m referring specifically to 6f07ac2:
cmd/gc: pad structs which end in zero-sized fields
For a non-zero-sized struct with a final zero-sized field,
add a byte to the size (before rounding to alignment). This
change ensures that taking the address of the zero-sized field
will not incorrectly leak the following object in memory.
reflect.funcLayout also needs this treatment.
Fixes https://github.com/golang/go/issues/9401
@ydnar Yes, that would kick in if you choose to put this field last in a struct. I don't see any reason to treat it differently. For all purposes other than it's special purpose, it's just a field.
Change https://go.dev/cl/581316 mentions this issue: cmd/compile: wasm32-specific structs.HostLayout changes
Would the field be zero sized if it's the last _ field in a struct?
We should probably document that "By convention, this field should be placed first in a struct." That's a good convention to have regardless.
@cherrymui pointed out that, while it's important that an addressable zero-sized field at the end of a struct must have non-zero size, that we could carve out zero-sized _
fields from this rule. Algorithmically, we would first strip zero-sized _
fields at the end of the struct, and then append a byte if the remaining final field is zero-sized. This is an implementation detail, and is something we could decide to implement in the future. It would remove a minor foot-gun.
@cherrymui pointed out that, while it's important that an addressable zero-sized field at the end of a struct must have non-zero size, that we could carve out zero-sized
_
fields from this rule.
This seems to imply a change to reflection: https://go.dev/play/p/TfYcdEwAACm
Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group
The proposal is to add
package structs
type HostLayout struct{}
that can be added as a field named _
in a struct. This would have no significant effect in most tools, but a compiler could use it as a hint about laying out the struct. Of course there is an effect for type equality, since a struct with one of these fields is different from a struct without, but that’s exactly what we want if the compiler is using it to hint a different layout.
This seems to imply a change to reflection: https://go.dev/play/p/TfYcdEwAACm
Oh, bother. (Summary of the code: reflect
lets you reference an _
field, take it's "address", and then get that as an unsafe.Pointer
, making this field, in effect, addressable. This, despite the fact that it's an unexported, unnamable field.)
Oh, bother. (Summary of the code: reflect lets you reference an _ field, take it's "address", and then get that as an unsafe.Pointer, making this field, in effect, addressable. This, despite the fact that it's an unexported, unnamable field.)
Maybe we want to disallow that? I would think reflection allows what one can do in the language spec, but not more than that. That will be a separate proposal, though.
Sorry to come late to the party but there are a few other directives we should consider to add to this structs package: namely
type NoUnkeyedLiterals struct{}
type DoNotImplement interface{
ProtoInternal(DoNotImplement)
}
type DoNotCompare [0]func()
type DoNotCopy [0]sync.Mutex
These are actually pretty common since the Go protobuf code uses this kind of pseudo directives: https://github.com/protocolbuffers/protobuf-go/blob/master/internal/pragma/pragma.go So I think they will pass the bar of being common enough to be included in the standard library.
@bjorndm , yep. That's one of the reasons we proposed structs
for this. It would be a great place for further marker types. Those, of course, would be separate proposals.
Ok, I will split it off then once this is accepted.
There is a question here about whether "HostLayout" should change based on things like CFLAGS, which in theory can change the "host layout" used by the C compiler. It sounds like we should define that HostLayout provides only the default host layout, and it is not affected by (does not even look at) CFLAGS. The default host layout is what is going to work for shared libraries, kernel data structures, and so on.
Of course, cgo already works out the effect of the CFLAGS for the C types that it generates, because it invokes the C compiler to decide the layout of those types. So cgo is unaffected by this.
Note also that go/types does not really need to worry about any of this. It can define its own "Host" layout.
The effect of HostLayout right now is a no-op. This is only laying the groundwork for changing the layout of fields in structs that don't say HostLayout, or for changes in wasm.
Should we make (relevant) CFLAGS be part of a host definition? (I don't need a fast answer to this.)
I don't think so. We would have to figure out how to carry them in. If it's needed it's something that can be left for later.
No change in consensus, so accepted. 🎉
This issue now tracks the work of implementing the proposal.
— rsc for the proposal review group
The proposal is to add
package structs
type HostLayout struct{}
that can be added as a field named _
in a struct. This would have no significant effect in most tools, but a compiler could use it as a hint about laying out the struct. Of course there is an effect for type equality, since a struct with one of these fields is different from a struct without, but that’s exactly what we want if the compiler is using it to hint a different layout.
Will field types also get HostLayouted automatically?
I think it is not, otherwise, unsafe.Sizeof(a)
and unsafe.Sizeof(b.a)
are not guaranteed to equal.
Report error when a HostLayouted struct has a field of a non-HostLayouted type?
type A struct {
x byte
y int64
z byte
}
type B struct {
_ structs.HostLayout
a A
}
var a A
var b B
IMHO, the structs.AlignN should be supported in the initial release of the structs
package, at least structs.Align8
should be supported, as it has been adopted in atomic.Uint64/Int64
.
Will field types also get HostLayouted automatically?
I'm not sure I fully understand what you're asking, but in terms of your example, the layout of A
must not change just because it's included in B
. This would break a lot of type rules beyond just unsafe.Sizeof
. For example, you can get a value of type *A
from either &a
or &b.a
, so the layout must be the same in both cases.
IMHO, the #19057 should be supported in the initial release of the structs package
We're aiming to define structs.HostLayout
in Go 1.23 because it's a stepping stone for other issues (notably: supporting type-safe pointers in go:wasmexport and addressing alignment issues in wasm32 in the near term, and eventually being able to reorder struct fields in the long term, though that one obviously has many moving parts). We can also land it in the next week and a half before the freeze because the definition today is literally just an empty struct and that gives people a smooth transition into semantic meaning in Go 1.24.
We'd love to do alignment markers, but that's not going to happen in the next week and a half.
-
What happens if I embed a type with a HostLayout field? Like
type A struct { x struct { _ HostLayout } }
I think the answer is A is also host layout, but we should spell that out.
-
What happens if I have of a field of type [0]HostLayout (or any array of HostLayout)?
type B struct { _ [0]HostLayout }
I think if the answer to 1 is "A has host layout", this B also must have host layout, because B isn't so different from
type C struct { x [1]struct { _ HostLayout } }
which isn't so different from A.
I interpret these differently, and narrowly. HostLayout is not and should not be viral "up" or "down", nor should its signal properties survive various type transformations.
For the up case specifically, I could have some larger Go type that includes some data that is passed to/from some host-linked call. E.g.
type Foo struct {
GoSideStuff SomeTypeWithoutHostLayout
HostSideStuff SomeTypeWithHostLayout
MoreFields MoreTypesWithoutHostLayout
}
The only type that has host layout is SomeTypeWithHostLayout
. If I wanted the enclosing type Foo to have host layout, there is a way to get that, and there is a reason to not want it, so it should not inherit from its fields.
In the "down" case, perhaps it should be an error if nested structs lack a host layout marker since that indicates a likely mistake, but they should not automatically inherit it. That would be confusing to tools and the type system; the reason we use a marker type is so that the types with different layout are also, obviously, different types. Consider this example:
type HasHostLayout struct {
_ structs.HostLayout
// some primitive typed fields affected by the layout
...
SomeField SomeType
}
type SomeType struct {
a, b int8
x int32
c, d int8
}
var x SomeType // absolutely positively has no host layout
var y HasHostLayout
var ap []*SomeType = []*SomeType{&x, &y.SomeField}
What are the layouts of the structs referenced by pointers ap[0]
and ap[1]
?
My plan for the signal types is that they are intended only to be signal types, and that there is no grand theory of inheriting properties any more than is required by their intended semantics. If a field has a type that is structs.HostLayout
, exactly that type, then the enclosing structure uses host layout for its fields. The end. [0]structs.HostLayout
is a different type, therefore, no effect. Perhaps the proposal should have made that more clear, but since they don't have semantics yet, we can more loudly define their semantics that way when the time comes.
If a programmer wants host layout, this defines a mechanism, use that mechanism, as defined. Don't infer the existence of mechanisms that were not defined, those won't work. (Why would you do that, anyway?)
My larger goal, in general, is to take weird host-specific stuff that complicates life for plain Go programmers, and wall it off so that plain Go programming is better/easier/faster. Defining this narrowly is the best way to advance that goal (I think).
Okay, I can buy that argument.
One thing that worries me though is arrays. E.g., suppose a 32-bit host has a rule that int64 must be 8 byte aligned. How do I create an array of int64s with host layout? It would be nice if you could write
struct {
_ structs.HostLayout
b byte
x [16]int64
}
But I agree that HostLayout shouldn't (and can't) "reach down". So I think what you have to write is
struct {
_ structs.HostLayout
b byte
x [16]struct { _ structs.HostLayout; v int64 }
}
That's cumbersome, but at least v
will clearly be adequately aligned. In this case, because alignment of a type is a property of the type, this will force the array type to also be aligned, which will force x
to be aligned.
Maybe that's good enough. Maybe we don't need complicated composition rules for HostLayout itself because any important implications become properties of the type that can then flow up (also, I can't think of any properties besides alignment this would apply to).
Arrays are an issue, but besides what you propose, I think we could get that alignment with
_ structs.HostLayout
b byte
_ [0]struct { _ structs.HostLayout; v int64 }
x [16]int64
this relies on (1) even with HostLayout activated, the Go compiler continuing to apply its zero-sized alignment rules, and
(2) the Go compiler not gratuitously inserting alignment-reducing padding between fields. It makes some of the code less ugly, and the declaration a bit uglier. Or maybe we make a special rule for embedded arrays of primitive types in such a struct; [N]whatever
is equivalent to N copies of whatever
, right?
About naming: package encoding/binary
has NativeEndian
, not HostEndian
.
@dolmen, that's true but NativeLayout doesn't make as much sense as HostLayout.
If this had come first maybe we'd have done HostEndian, but maybe not.
They're just different.
In proposal review, we talked about the case of
struct {
_ structs.HostLayout
b byte
x [16]int64
}
and concluded that it's okay for HostLayout to affect the order and offsets of fields, including x
. It certainly can't change the layout within the array because &x
must have the same layout as any other [16]int64
, but the host layout rules can talk about alignment of arrays of int64
just as they can talk about the alignment of int64
.
A related question, given:
type T struct {
x structs.HostLayout
y int64
}
type U struct {
T
z float64
}
Does U get host layout? Because T is embedded, U technically has a U.x
field of type HostLayout, though it also has a U.T.x
field. I think we can just make up the rule we want here, but it's something we need to consider and specify.
I don't think that U
should get host layout in that example. It should have a field of type T
, which has host layout, followed by a field of type float64
. The fact that U
embeds a field of type struct.HostLayout
seems like a technicality.
To put useful information in one place, from the CL, there was discussion of whether the struct needs an internal field of package-private zero-sized type, and the answer is that yes it should have one, what we do with it in the future is TBD but it provides an option for the future implementation. The "test" program has types T, AHL,HL, U, V, W, X, Y, Z, G, GP where:
- T embeds
structs.HostLayout
directly - HL is
type HL structs.HostLayout
- AHL is
type AHL = structs.HostLayout
(type alias, ought to act just likestructs.HostLayout
) - U embeds
HL
- V has a
structs.HostLayout
field - W has a
HL
field - X embeds
T
(which embedsstructs.HostLayout
) - Y embeds
V
(which has astructs.HostLayout
field) - Z embeds
AHL
- G[P] is generic with a field of type P
- GP is
G[structs.HostLayout]
With an internal private tag field, it is straightforward (I've written the code for testing) to implement either "{T,U,V,W,Z,GP} have host layout" or "{T,V,Z,GP} have host layout". I think this gives us the right amount of virality; my preference (which is not necessarily everyone's , but it's the proposal-author's intent) is that this is supposed to also be a signal to readers that a type is special and the field order matters, and writing cute code that obscures this signal is anti-recommended. I'm not super thrilled about the GP
case. Yes, you can write it that way, but please don't. My best-to-least ordered preferences, which may not be what we get, are: {T,V,Z}, {T,U,V,W,Z}, {T,V,Z,GP}, {T,U,V,W,Z,GP}. These are all acceptable, I just like the first one better, and if I could convince vet to whine about the last two I would ("instantiating generic type with structs.HostLayout is confusing, please don't")
But maybe other people understand this differently.
package main
import (
"fmt"
"structs"
)
type T struct {
structs.HostLayout
x, y int
}
type HL structs.HostLayout
type AHL = structs.HostLayout
type U struct {
HL
x, y int
}
type V struct {
_ structs.HostLayout
x, y int
}
type W struct {
_ HL
x, y int
}
type X struct {
T
z int
}
type Y struct {
V
z int
}
type Z struct {
AHL
z int
}
type G[P any] struct {
_ P
z int
}
type GP G[structs.HostLayout]
func main() {
t := T{x: 1, y: 2}
u := U{x: 3, y: 4}
v := V{x: 5, y: 6}
w := W{x: 7, y: 8}
x := X{z: 9}
y := Y{z: 10}
z := Z{z: 10}
g := GP{z: 10}
fmt.Printf("t=%+v\nu=%+v\nv=%+v\nw=%+v\nx=%+v\ny=%+v\nz=%+v\ng=%+v\n", t, u, v, w, x, y, z, g)
}
The two versions of isHostLayout...
for cmd/compile/internal/types/size.go
:
func isHostLayoutType(t *Type) bool {
if sym := t.Sym(); sym != nil {
return sym.Name == "HostLayout" && sym.Pkg.Prefix == "structs"
}
return false
}
func isHostLayoutTypeByField(t *Type) bool {
et := t.Kind()
if et != TSTRUCT {
return false
}
fs := t.Fields()
if len(fs) != 1 {
return false
}
if sym := fs[0].Type.Sym(); sym != nil {
return sym.Name == "hostLayout" && sym.Pkg.Prefix == "structs"
}
return false
}
Is there an existing open issue for NoCopy
(that I am failing to find) or I should open one?
(it's great to see the structs
created but it looks a bit bare with just HostLayout)
Edit: I was pointed to #67265
The effect of HostLayout right now is a no-op. This is only laying the groundwork for changing the layout of fields in structs that don't say HostLayout, or for changes in wasm.
So cgo is unaffected by this.
If I were to type-cast a C-struct value to a Go-struct value with the same field alignment, can I rely on this behavior in the future? Or will those Go structs still need structs.HostLayout
?
We’re adding support for struct.HostLayout
to wit-bindgen-go
for generating WASI 0.2+ interfaces. To support earlier versions of Go, it implements a polyfill for Go 1.22 and lower, and a type alias type HostLayout = structs.HostLayout
on Go 1.23 or later.
If a struct embeds an alias for structs.HostLayout
, should that have the same effect as embedding structs.HostLayout
directly?
As per #66408 (comment):
AHL is type AHL = structs.HostLayout (type alias, ought to act just like structs.HostLayout)