Hi all,
there have been some discussion on this in the past (e.g. Compilation conditions for word size) and @xwu provided an implementation, but there was never a proposal to actually add this. I think this is a very useful feature, so I took it over, created an updated PR and am now creating this pitch.
Looking forward to your feedback.
Introduction
As a multi-platform language Swift supports various CPU architectures with different
pointer sizes. The pointer size can be checked at runtime using MemoryLayout
, but
it is currently not possible to use this information at compile-time. This proposal
aims to add a compile-time conditional to check the pointer size in bits for the
given target architecture.
Motivation
Currently the only way to branch on pointer size at compile time is to list every
supported CPU that uses the specific pointer size as follows:
#if arch(i386) || arch(arm) || arch(arm64_32) || arch(wasm32)
This code is error prone and hard to maintain. Whenever a new target architecture
is added, code has to be carefully examined and updated for the new architecture.
Being able to branch on the pointer size at compile time would eliminate the need
to update code like this and instead only require the pointer size to be configured
when adding the new target architecture to the compiler.
Proposed solution
We are proposing to add a new compile-time conditional pointerBitWidth
, that
checks if the target architecture uses the specified pointer size.
Usage:
struct MyStruct {
#if pointerBitWidth(32)
let myProperty: Float
#elseif pointerBitWidth(64)
let myProperty: Double
#else
#error("Unsupported pointer size.")
#endif
}
Source compatibility and ABI
This change is purely additive.
Alternatives considered
An alternative appraoch would be to use the existing runtime mechanism instead.
Example:
if MemoryLayout<UnsafeRawPointer>.size == 4 { // system uses 32-bit pointers
// ...
}
This should generally be constant folded by the compiler, but it is limited
in that it can only affect runtime control flow and not be used for conditionally
available functions or type layouts.
Example:
struct MyStruct {
if MemoryLayout<UnsafeRawPointer>.size == 4 {
let myProperty: Float
} else {
let myProperty: Double
}
}
This code is invalid and will cause a compiler error.