[swift-evolution] [proposal]Decouple definition of Int8 from target char type

William Dillon william at housedillon.com
Thu Feb 25 21:47:08 CST 2016

Hi All,

(For best viewing, use a fixed-width font with this email)

While porting Swift to ARM/Linux (and while observing other ports, such as SwiftAndroid) several of my collaborators and I have noticed inconsistencies in the handling of char.  I’ve taken the liberty of producing a table to summarize these differences that will hopefully illuminate the problem.

char           ARM         mips         ppc        ppc64       i386      x86_64
Linux/ELF  unsigned[1]  unsigned[2]  unsigned[3] unsigned[4] signed[5] signed[6]
Mach-O       signed[7]     N/A        signed[7]   signed[7]  signed[7] signed[7]
Windows    —=-=-=-=-=-=-=-=-=-=-=-=-=-=- signed —=-=-=-=-=-=-=-=-=-=-=-=-=-=-[8]

Swift currently maps the Int8 type to be equal to the char type of the target platform.  On targets where char is unsigned by default, Int8 becomes an unsigned 8-bit integer, which is a clear violation of the Principle of Least Astonishment.  Furthermore, it is impossible to specify a signed 8-bit integer type on platforms with unsigned chars.

This proposal aims to address the problem by defining the CChar type to equal whatever type the target defines as char.  Further, Int8 and UInt8 will always be their advertised signedness.  The current status quo requires extensive special-casing (or casting) for compilation to succeed, and if it does, the tests require specialization to the underlying type of the target device.

We have come across this issue several times during code review of our patches, and I’ve included a sampling of these to provide some context to the discussion:


In these discussions we obviously struggle to adequately solve the issues at hand without introducing the changes proposed here.  Furthermore, other than completely disabling the test, there is no other satisfactory way to make the last remaining failure on Linux/ARM (c_layout.sil) pass.

The implementation of this proposal requires changes to the way Swift imports these types.  The impact of these changes will be fully evaluated, and an sample implementation will likely be complete, prior to the submission of this proposal for scheduling and consideration.  We do anticipate some changes to user code, the standard library, and Foundation may be required.

These changes should happen during a major release.  Considering them for Swift 3 will enable us to move forward efficiently while constraining any source incompatibilities to transitions where users expect them.  A stated goal of Swift 3 is to improve portability, and these changes are, to us, necessary to consider such a goal a success.   Code that works properly on each of these platforms now is already resilient to changes in the implementation of char, and should continue to work.  Further, the implementation of this proposal will identify cases where such a problem exists, but for which the symptoms have not yet been identified.

The proposed new mapping of types is as follows:

    C type    |   Swift type
         char |   CChar
unsigned char |   UInt8
  signed char |    Int8

I appreciate any comments, concerns, or questions.
- Will

[1]: http://www.eecs.umich.edu/courses/eecs373/readings/ARM-AAPCS-EABI-v2.08.pdf
[2]: http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf
[3]: https://uclibc.org/docs/psABI-ppc.pdf
[4]: http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html
[5]: http://www.sco.com/developers/devspecs/abi386-4.pdf
[6]: http://www.x86-64.org/documentation/abi.pdf
[7]: *proof by construction* (is it signed by convention?)
$ cat test.c
char _char(char a) { return a; }
signed char _schar(signed char a) { return a; }
unsigned char _uchar(unsigned char a) { return a; }

$ clang -S -emit-llvm -target <arch>-unknown-{windows,darwin}

and look for “signext” OR “zeroext" in @_char definition

[8]: Windows char is signed by convention.

More information about the swift-evolution mailing list