Repository navigation
gen-c: real Zig builtins (@abs, @intFromEnum, @min, ...) reach the C verbatim -- 85 of 1362 outputs, 769 sites #7297
Description
What happens
t27c gen-c lowers a bare abs(x) to the t27_abs macro (a C11 _Generic over fabs/fabsf/llabs), but it writes the Zig spelling of the same call, @abs(x), into the C as it stands. gcc reads the @ as a stray character and then calls C's own int abs(int):
module Probe;
pub fn d(x: f64) -> f64 {
return @abs(x);
}
test "abs of a negative double" {
assert(d(-2.5) == 2.5);
}
$ t27c gen-c probe.t27 > probe.c ; echo $?
0
$ grep -n abs probe.c | head -1
28: return @abs(x);
$ cc -std=c11 -c probe.c
probe.c:28:12: error: stray '@' in program
probe.c:28:13: warning: implicit declaration of function 'abs' [-Wimplicit-function-declaration]
probe.c:28:17: warning: 'abs' argument 1 type is 'double' where 'int' is expected ... [-Wbuiltin-declaration-mismatch]
Master's t27c writes the same line 28.
How much
Measured on the Railway lab with t27c built from 403b27f + #7242 + #7281 + #7292, running gen-c on all 1363 .t27 files of the #7191 fourth-slice tree (1362 produce output):
- 116 outputs contain a
@name(call, 1219 sites in all. - 85 outputs, 769 sites, call one of the 28 builtins t27c knows (the list is in A call to a builtin that does not exist typechecks clean, generates, and reaches the C verbatim -- 41 specs classed Working do it #4561). Without
@setEvalBranchQuota, 59 outputs. - Per builtin:
@setEvalBranchQuota402,@abs91,@intFromEnum81,@floatFromInt51,@min33,@bitCast22,@sqrt17,@floatCast11,@exp11,@max10,@intFromFloat8,@enumFromInt8,@log6,@round5,@rem5,@mod5,@trunc1,@floor1,@ceil1. - The other 450 sites name no Zig builtin (
@len,@print,@contains, ...). That is A call to a builtin that does not exist typechecks clean, generates, and reaches the C verbatim -- 41 specs classed Working do it #4561's class, not this one.
Why it shows now
#7292 stops the use resolver from reading @abs as a reference to a spec's own abs. Six specs import math::constants whole and call abs only as @abs: ml/activation/gelu_activation, ml/activation/sigmoid_activation, tri/math/bezier, tri/math/constants, tri/math/matrix and tri/math/probability.
- Before use resolver: a builtin call @pow(...) is read as a reference to pow and splices the spec's own pow #7292,
math/constants.t27'sabswas spliced into each of them as dead code, and itsdouble abs(double)gave gcc's error recovery a prototype for the call after the stray@. - After it,
cc -fsyntax-onlyreports the same number of errors on all six, but more-Wbuiltin-declaration-mismatchwarnings, e.g.probabilityfrom 5 to 56. - None of the six outputs compiles, before or after.
Proposal
Route each sigil builtin that has a C meaning through the lowering its bare spelling already has, as the Rust backend does for both spellings in zig_builtin_to_rust:
@abstot27_abs;- the libm names (
@sqrt,@exp,@log,@floor,@ceil,@round,@trunc,@sin,@cos,@tan) to their C functions; - the casts (
@intFromEnum,@floatFromInt,@intFromFloat,@floatCast,@intCast,@as) to a C cast; @setEvalBranchQuota, a comptime hint, to nothing.
The emitter lives in bootstrap/src/compiler.rs, which carries FROZEN_HASH.
Acceptance criteria
- The probe above compiles with
cc -std=c11 -cwith 0 errors and 0 warnings, and a test that checks it fails with the change reverted. - The number of real-builtin
@name(sites in the corpusgen-coutput drops from 769, and the new number is stated. - No output that passed
cc -std=c11 -fsyntax-onlybefore fails after. - Every seal whose
gen_hash_cchanges is listed.
Boundary
bootstrap/src/compiler.rs
User Scenarios
- Given a .t27 file that calls
@abs(x)on a floating-point value, whent27c gen-ccompiles it, then the generated C file contains a call to thet27_absmacro (or equivalent C11_Genericselection) instead of the literal token sequence@abs(x). - Given a .t27 file that calls any of the 28 Zig builtins that have a C lowering (e.g.,
@intFromEnum,@min,@sqrt,@setEvalBranchQuota), whent27c gen-ccompiles it, then the generated C file contains the corresponding C construct (cast, function call, macro, or nothing for comptime hints) and no stray@character. - Given the full Railway fourth-slice corpus (1362 files that produce output), when
t27c gen-cruns on all of them, then the number of real-builtin@name(sites in the combined C output is strictly less than 769, and every file that previously passedcc -std=c11 -fsyntax-onlystill passes.
Requirements
FR-001: The C emitter in bootstrap/src/compiler.rs MUST lower @abs to the t27_abs macro (C11 _Generic over fabs/fabsf/llabs) for all integer and floating-point argument types.
FR-002: The C emitter MUST lower libm builtins (@sqrt, @exp, @log, @floor, @ceil, @round, @trunc, @sin, @cos, @tan) to their corresponding C math.h functions with correct type suffixes.
FR-003: The C emitter MUST lower cast builtins (@intFromEnum, @floatFromInt, @intFromFloat, @floatCast, @intCast, @as) to explicit C casts.
FR-004: The C emitter MUST lower @min and @max to the t27_min/t27_max macros (or equivalent _Generic selections) matching the bare min/max lowering.
FR-005: The C emitter MUST lower @setEvalBranchQuota to nothing (elide the call entirely) because it is a comptime hint with no runtime semantics.
FR-006: The C emitter MUST apply the same lowering for sigil (@name) and bare (name) spellings of every builtin listed above, consistent with the Rust backend's zig_builtin_to_rust.
FR-007: After the change, the probe example in the issue MUST compile with cc -std=c11 -c producing zero errors and zero warnings.
FR-008: No output file that previously passed cc -std=c11 -fsyntax-only MUST fail after the change.
Activity
t27c: a spliced `use` becomes a comment, and `@builtin` is not a refe…
gHashTag commentedon Oct 7, 2026
Reopened 2026-10-07: the bulk close of issues without a
## Boundarysection was reverted by the owner. Nothing to do here; this comment replaces the earlier close notice.