2026-04-06
With 0.7.11 we’ve reached the end of the 0.7 era. It’s been a really good year for C3, improving on rough edges and expanding the stdlib.
This release is headlined by an updated matrix library. Aside from that, it’s a refinement release, bringing numerous fixes but no major changes.
constdef inference through binary operationsconstdef is often used to define masks:
constdef Foo{ AUDIO = 0b01, VIDEO = 0b10, /* ... */}In 0.7.10 inference worked through assignment but not expressions:
Foo f = AUDIO; // Okf = Foo.AUDIO | Foo.VIDEO; // Ok// f = AUDIO | VIDEO - this is an errorFrom 0.7.11 onwards, the inference works:
f = Foo.AUDIO | Foo.VIDEO; // Okf = AUDIO | VIDEO; // Also ok in 0.7.11@weak@weak, which changes linkage, now also supports having multiple definitions of the same declaration in the same source code, allowing the non-”weak” definition to win. This allows things like changing code from this:
fn void foo() @if(env::POSIX){ io::printn("Works!");}
fn void foo() @if(!env::POSIX){ abort("Unsupported foo()");}To this:
fn void foo() @if(env::POSIX){ io::printn("Works!");}
fn void foo() @weak{ abort("Unsupported foo()");}Builtins (functions prefixed with $$, such as $$unreachable) are intended to be accessed through standard library macros, not used directly. They are considered internal and may change without warning.
This wasn’t previously clear, and some code ended up using them directly. The compiler will now issue a warning when such builtins are used outside the standard library.
Before 0.7.11, the language allowed empty enums. In practice, they were not fully supported and could lead to incorrect behavior.
Given their limited usefulness and the inability to define a valid zero value, empty enums have been removed from the language.
C3 now also detects large temporaries when creating slices on the stack.
The big change is the updated Matrix library. The new matrix type is column major, aligning it with most graphics and math libraries. It has also undergone quite an overhaul, with methods and functions updated and fixed. The default aliases are now based on floats rather than doubles, which fits with common usage.
The predefined aliases are:
Quat - quaternionMat2 - 2x2 matrixMat3 - 3x3 matrixMat4 - 4x4 matrixVec2 - 2d vectorVec3 - 3d vectorVec4 - 4d vectorRect - 2d rectangleThe matrix perspective and ortho, project and unproject functions are now right-handed [0,1].
std::mem::allocator is deprecated and split into std::core::mem::allocators containing allocators and std::core::mem::alloc for various allocation methods. This means replacing most allocator::* calls with alloc::*, e.g. allocator::calloc becomes alloc::calloc.@unaligned_load and @unaligned_store are deprecated in favour of mem::load and mem::store, which also supports unaligned volatile load/store operations.encode_into and decode_into.entropy module for generating cryptographically secure random bytes.random::seeder no longer uses temp memory.Printable and can be used directly with printfto_format method.member_eq.always_assert macro, which asserts even in unsafe mode.file::last_modified was added.SubProcess was renamed Process and refreshed with new, more streamlined, functions.short_name() and @short_name() to get the unqualified fault name, e.g. io::EOF becomes EOF.On most platforms, the C3 compiler is linked with custom-built LLVM libraries, which reduces the need to support older versions of LLVM.
0.7.10 was incompatible with LLVM 22, which is fixed in this version.
With 0.7.11, MUSL-based builds of the compiler are available on Linux.
0.7.10 brought automatic download of the MSVC SDK without needing external scripts. In 0.7.11, this is extended to support Android, with the goal of bringing in more targets, such as the MacOS SDK for effortless cross-compilation.
0.7.11 brings many major and minor bug fixes, see the complete release notes for details.
Next up will be 0.8.0. As usual, this means there will be breaking changes. The most obvious target is all the deprecated functionality, from enum Foo : const int to the old matrix library.
However, the big upcoming change is the so-called “Szmageddon”: C3 will change from unsigned sizes (usz) to signed sizes by default. This will also affect type promotion rules and literal types.
This release wouldn’t have been possible without the C3 community. I’d like to extend a deep thank you to all who have contributed, both through filed issues, PRs and just plain discussions.
Stdlib: Alexandru Paniș, Book-reader, Bram Windey, Dave Akers, Disheng Su, Flanderzz, Konimarti, Manu Linares, LowByteFox, Siladi, Skunky, Technical Fowl, Zack Puhl
Compiler & toolchain: Dmitry Atamanov, Lucas Alves, Manu Linares, Nmurrell07, Rodrigo Camacho
CI/Infrastructure: Manu Linares, Mehdi Chinoune, Sisyphus1813, Zack Puhl
constdef inference through binary expressions: Foo f = Foo.AUDIO | Foo.VIDEO can be written Foo f = AUDIO | VIDEO;@weaklink for just affecting linkage.c3c for Linux. #2949@weak now allows direct overriding of @weak definitions with a real definition.c3c fetch-sdk <target> (windows, android) and added support for automatic Android NDK (r29) download. Better progress bar. #3019$$acos, $$asin, $$atan, $$cosh, $$exp10, $$sinh, $$tan and $$tanh.xoshiro and xoroshiro PRNG variants. #3027any_to_enum_ordinal and any_to_int to improve error when passed an empty any. #2977keccak and Keccak-based hash functions: sha3, shake, cshake, kmac, turboshake, tuplehash, and parallelhash. #2728fault.short_name and fault.@short_name to get just the fault name for both run and compile time. #3002Printable.to_format functionality for DateTime.SubProcess/process::create/process::execute_stdout_to_buffer deprecated, replaced by Process/process:spawn/process::run_capture_stdout.Argon2 memory-hard hashing with associated tests. #2773rejection, project, implement unproject.cubic_hermitesq_magnitude, barycenter, towards, ortho_normalize, clamp_mag, use length_sq, barycentric, move_towards, orthonormalize, clamp_length instead.math::deg_to_rad and math::rad_to_deg respects the underlying type, returning float on a float argument.float.to_radians and float.to_degrees and the same for double.Quat, Mat2, Mat3 and Mat4, Vec2, Vec3, Vec4 aliases.is_normalized to Quaternion and floating point vectors.quaternion::from_rotation and quaternion::from_normalized_rotationRect type.matrix::frustum.math::@abs for compile time abs.Errno a constdef containing all definitions. Deprecated libc::errno constants.random::seeder no longer uses temp memory.member_eq. #2801std::core::mem::allocator deprecated and split into std::core::mem::allocators containing allocators and std::core::mem::alloc for various allocation methods.always_assert builtin macro.entropy module to generate cryptographically-secure random bytes. #3022TIMEOUT fault definition. #3022encode_buffer and decode_buffer. Those are replaced by encode_into and decode_into with dst being the first argument. #3055hex::encode_bytes and hex::decode_bytes are deprecated in favour of hex::encode_bytes_into and hex::decode_bytes_into which has dst the first argument. #3055@unaligned_load and @unaligned_store. Use mem::load and mem::store instead.@deprecated in function contracts would be processed twice, causing a compilation error despite being correct.read_varint and write_varint did not work properly for ulong and wider.io::EOF.nameof would yield just EOF whereas resolving it at runtime would (correctly) yield io::EOF.$stringify would incorrectly capture lambdas. #2986String was not implicitly @constinit #2983-Os #3015--safe=no #3012.double[<*>].max and .min were broken.{ .xy = 1 } constant initializer vector to a function taking a vector, hitting vec->array conversion. #3035alias FOO = _BAR the compiler would incorrectly would say that _BAR wasn’t a constant.@nodiscard, @maydiscard and @noreturn weren’t properly handled for function type declarations.$defined with body expansion would not correctly check if parameters were the right type.mask_from_int would miscompile on some platforms.@packed would cause incorrect lowering #3000test(...(int[2]){ 88, 99 }, a: 123) could cause the compiler to crash.&some_global[0] was incorrectly considered a global constant when some_global was a slice.$$builtin function would crash the compiler.$$builtin function.int[type()] type.$$str_find or $$str_hash arguments were invalid, causing a crash.void{} would be looked up as generic in some cases and cause a crash.$foreach in some cases the elements was an untyped variable which would cause a crash.@ensure and @require could contain rethrows, which then would crash the compiler.$defined($Type) and $Type is a typeid.{1, 2}[n] = 33 wasn’t marked as an error and resulted in a crash.$foo++ would crash the compiler if the variable wasn’t initialized.Check out the documentation or download it and try it out.
Have questions? Come and chat with us on Discord.
Discuss this article on Reddit or Hacker News.