For existing structs in library-evolution-enabled libraries on ABI-stable platforms, at least. On the other hand, it isn't necessarily a problem to not have a strong layout guarantee, if the consumers of the data are using the same struct definition in the same version of the compiler, or using other reflection metadata emitted by the same compiler to recover the layout.
It would be nice if we had a way to opt-in to some kind of explicitly defined layout; most structs and enums don't need a hard layout constraint, but in other languages (C, Pascal, some variants of BASIC) it's common to use record types to represent memory layouts. In Swift today, we either have to drop down to unsafe pointers (or something built on them), or import structs from C/C++ to get somewhat well-defined layout.
I'm not saying that should be part of this pitch, just that it would be nice to have. If someone is going to work on that, I have some ideas about it…
@kubamracek Would you mind elaborating on which function conventions will be supported as members of a structure/tuple that's emitted into a section? You use @convention(c) in an example, and you and I have discussed this privately a few times, but it would be good for the proposal to make clear exactly what will or won't be supported.
This is described in the Constant Values proposal: swift-evolution/proposals/0nnn-const-values.md at const-values · artemcm/swift-evolution · GitHub
(I know you are specifically interested in what will @section allow, and feel free to keep asking more
but some of the answers will belong in the the @section proposal and some in the @const one.)
Indeed, my focus is @section but obviously I need both. Would you mind adding a reference to that part of the other pitch for clarity's sake? Thank you!
(I brought it up because @Erik_Eckstein mentioned in a GitHub issue that the current experimental @_section allows for @convention(swift) functions, and I wanted to get us all on the same page.)
Thanks for pushing forward on this!
One thing that might be just related to my quick skimming, but might be good to make more clear is that @constInitialized feels like it may imply immutability. I had the benefit of just asking the question so I am no longer confused, but the initial pass made it seem like it was immutable.
The second thing is that I can see @section and @constInitialized as being orthogonal. Consider something like the following:
struct S {
char b[1'000'000];
};
S s;
That C(23) bit of code creates a visible, mutable, buffer that is placed into the BSS. While this is possible to argue is constant initialized (it is zero'ed memory), this does not take (virtually) any space in the file - the symbol is recorded with the requested size. The loader will allocate the virtual address space appropriate for it, but it takes nearly 0 size on disk. This makes me feel that @section and @constIntiailized should not necessarily be tied together, but as different axes of control that are often used together.
Unrelated to my previous comments… would it be possible to allow @section on local symbols if they do not capture any state and are constant-evaluatable?
Our specific use case is for exit tests where we need to emit some metadata during macro expansion. We currently do so by shoving it in a locally-declared enum, which otherwise satisfies the requirements of the compiler today, but it'd be nice if we didn't need the enum at all.
What do you mean by "local symbol"? Can you give a code example?
For example, the following test:
@Test func explodesOnImpact() async {
await #expect(exitsWith: .failure) {
fatalError()
}
}
Currently expands to something like:
@Test func explodesOnImpact() async {
await Testing.callExitTest(id: 12345) {
enum ExitTestContainer {
@_section(".sw5test$B")
static let testRecord = (id: 12345, ...)
}
}
}
Which allows the testRecord value to be emitted into the binary and discovered later at runtime. It'd be useful, although not critical, if we didn't need the ExitTestContainer type:
@Test func explodesOnImpact() async {
await Testing.callExitTest(id: 12345) {
@_section(".sw5test$B")
let testRecord = (id: 12345, ...)
}
}
(Nesting in a closure is still necessary because of how expression macro expansion works.)
Hm. I understand where you're coming from, but I don't think local variables are in scope at this point for either of the two proposals (constant values, section placement). CC @ArtemC in case he has more to add.