Skip to content

v0.2.2

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 31 Aug 19:35
· 47 commits to main since this release
v0.2.2
8d1fa09

Added

  • __int128 and unsigned __int128 in rucc-types, as integer kinds of their own rather than as a _BitInt(128) wearing a different name. The two are genuinely different types: __int128 is sixteen bytes aligned to sixteen on every target here, a _BitInt(128) is aligned to its granule, which is eight bytes on x86-64, and __int128 outranks long long where a _BitInt is ranked by its width alone. So __int128 + unsigned long long is an __int128, which is what both compilers answer and what a program relying on the extension expects. It is available on every target, because all three architectures are 64-bit and GCC has the type on every 64-bit target it supports, and it is deliberately not an extended integer type in the sense the standard means, which is what keeps intmax_t sixty four bits wide the way GCC has it.

  • The keyword table in rucc-lex, which is the first half of phase 7 and what turns an identifier into a word the grammar knows. The spellings are interned before any source is read, so their symbols are one run at the bottom of the interner and recognising a keyword is a subtraction and a bounds check rather than a string comparison or a hash of the text. Which spellings the dialect actually has is resolved once, when the table is built, rather than at every identifier, so restrict is a keyword from C99 and a variable name in C89 at no cost per token. Which word is a keyword in which dialect was measured rather than recalled, by compiling every candidate as a variable name against gcc 13.3 and clang in each of the ten dialects, with two ordinary identifiers along for the ride to catch a probe that had stopped measuring anything. Two of the answers are not what a reading of the standard suggests: restrict is not a keyword in -std=gnu89 although inline is, and asm is still not one in -std=c23, where __asm__ has to be written instead. The GNU spellings are keywords in every dialect including -std=c89, which is why headers are written with them, and where two spellings mean the same thing they are one keyword, so a parser never has to know which was typed. __alignof__ and _Alignof stay apart, because one asks for the alignment the target prefers and the other for the one the ABI requires.

  • Integer constants in rucc-lex, which is the piece of phase 7 that turns a preprocessing number into a value and a type. The type is the standard's table walk, a candidate list chosen by the base, the suffix and the dialect, walked in order until a type holds the value, and it is not the list a reading of the standard alone would give: C89 has unsigned long in the list for a decimal constant with no suffix and nothing has it after C89, which is why 18446744073709551615 is eight bytes under -std=c89 and sixteen under -std=c99, and gcc says so in as many words. Past long long a decimal constant reaches for __int128 rather than for an unsigned type, so 9223372036854775808 is a signed constant in gcc and an unsigned one in clang, and following gcc is what keeps its negation negative. Only the decimal list is signed types alone, which is the split behind 4294967295 being a long while 0xffffffff is an unsigned int. Every row was measured by writing the constant and asking _Generic what it is, against gcc 13.3 on x86-64 Linux and clang, rather than recalled, and the type comes from the target description, so the same constant is a long on Linux and a long long on Windows without the host having a say. The value is accumulated in a hundred and twenty eight bits with every step checked, which is one deliberate difference from gcc: its accumulator is sixty four bits, so 18446744073709551616 compiles there to zero of type int after a warning, and here it is refused. _BitInt constants get the narrowest type that holds them, which for a signed one counts the sign bit and is never less than two, so 1wb is a _BitInt(2) and 255uwb is an unsigned _BitInt(8), measured against clang because gcc 13.3 has no such type. A constant that uses a binary prefix, a digit separator, a wb suffix or an ll suffix before the dialect that standardised it is still converted and comes back with a remark, so the caller holding the span decides what -pedantic makes of it rather than the conversion deciding for it.

What's Changed

  • Add the keyword table and the dialect gate by @tamnd in #55
  • Add __int128 as an integer kind of its own by @tamnd in #56
  • Add integer constants to phase 7 by @tamnd in #57
  • Release 0.2.2 by @tamnd in #58

Full Changelog: v0.2.1...v0.2.2