diff --git a/lib/std/c/builtins.zig b/lib/std/c/builtins.zig index 2c03c1ceac..1d100369b9 100644 --- a/lib/std/c/builtins.zig +++ b/lib/std/c/builtins.zig @@ -188,3 +188,9 @@ pub fn __builtin_memcpy( pub fn __builtin_expect(expr: c_long, c: c_long) callconv(.Inline) c_long { return expr; } + +// __builtin_alloca_with_align is not currently implemented. +// It is used in a run-translated-c test and a test-translate-c test to ensure that non-implemented +// builtins are correctly demoted. If you implement __builtin_alloca_with_align, please update the +// run-translated-c test and the test-translate-c test to use a different non-implemented builtin. +// pub fn __builtin_alloca_with_align(size: usize, alignment: usize) callconv(.Inline) *c_void {} diff --git a/src/translate_c.zig b/src/translate_c.zig index d2c5cd6233..e63ced58e9 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -11,6 +11,7 @@ const math = std.math; const ast = @import("translate_c/ast.zig"); const Node = ast.Node; const Tag = Node.Tag; +const c_builtins = std.c.builtins; const CallingConvention = std.builtin.CallingConvention; @@ -1526,7 +1527,7 @@ fn transImplicitCastExpr( return maybeSuppressResult(c, scope, result_used, ne); }, .BuiltinFnToFnPtr => { - return transExpr(c, scope, sub_expr, result_used); + return transBuiltinFnExpr(c, scope, sub_expr, result_used); }, .ToVoid => { // Should only appear in the rhs and lhs of a ConditionalOperator @@ -1542,6 +1543,22 @@ fn transImplicitCastExpr( } } +fn isBuiltinDefined(name: []const u8) bool { + inline for (std.meta.declarations(c_builtins)) |decl| { + if (std.mem.eql(u8, name, decl.name)) return true; + } + return false; +} + +fn transBuiltinFnExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { + const node = try transExpr(c, scope, expr, used); + if (node.castTag(.identifier)) |ident| { + const name = ident.data; + if (!isBuiltinDefined(name)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO implement function '{s}' in std.c.builtins", .{name}); + } + return node; +} + fn transBoolExpr( c: *Context, scope: *Scope, @@ -4759,6 +4776,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N }, .Identifier => { const mangled_name = scope.getAlias(slice); + if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) { + try m.fail(c, "TODO implement function '{s}' in std.c.builtins", .{mangled_name}); + return error.ParseError; + } return Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name); }, .LParen => { diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index bda401d08c..10c3a04540 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1221,4 +1221,16 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + // See __builtin_alloca_with_align comment in std.c.builtins + cases.add("use of unimplemented builtin in unused function does not prevent compilation", + \\#include + \\void unused() { + \\ __builtin_alloca_with_align(1, 8); + \\} + \\int main(void) { + \\ if (__builtin_sqrt(1.0) != 1.0) abort(); + \\ return 0; + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 47d7c5d9eb..6aab4736a3 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3418,4 +3418,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const MAY_NEED_PROMOTION_HEX = @import("std").meta.promoteIntLiteral(c_int, 0x80000000, .hexadecimal); \\pub const MAY_NEED_PROMOTION_OCT = @import("std").meta.promoteIntLiteral(c_int, 0o20000000000, .octal); }); + + // See __builtin_alloca_with_align comment in std.c.builtins + cases.add("demote un-implemented builtins", + \\#define FOO(X) __builtin_alloca_with_align((X), 8) + , &[_][]const u8{ + \\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.c.builtins"); + }); }