Skip to content
6 changes: 1 addition & 5 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -10971,11 +10971,7 @@ lib.addCSourceFile(.{ .file = .{ .path = "src/lib.c" }, .flags = &.{
</p>
{#code_begin|exe|cImport_builtin#}
{#link_libc#}
const c = @cImport({
// See https://github.com/ziglang/zig/issues/515
@cDefine("_NO_CRT_STDIO_INLINE", "1");
@cInclude("stdio.h");
});
const c = @cImport(@cInclude("stdio.h"));
pub fn main() void {
_ = c.printf("hello\n");
}
Expand Down
2 changes: 2 additions & 0 deletions lib/compiler_rt/os_version_check.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is not auto translated from C.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know. Please note that I still need to go through the instances of thisfileisautotranslatedfromc; that needed to be added, and determine which ones are actually needed. As I said in Ian's review, I will construct them from @Type if they are truly needed.


const std = @import("std");
const testing = std.testing;
const builtin = @import("builtin");
Expand Down
2 changes: 2 additions & 0 deletions lib/std/fmt.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this has been discussed already, but for the uncommon correct uses of C pointers in std (testing functionality that interacts with them), how about using @Type to programmatically construct C pointer types? Since the check is implemented in AstGen, I believe that should still work, and it would avoid having to infect the entire file with the autotranslated status.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was discussed, and that was the consensus iirc.
If you look at my checklist I still have to look through the stdlib uses of the keyword and see if they are truly needed. I will construct with with @Type if they actually are needed 👍


const std = @import("std.zig");
const builtin = @import("builtin");

Expand Down
2 changes: 2 additions & 0 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std.zig");
const builtin = @import("builtin");
const debug = std.debug;
Expand Down
2 changes: 2 additions & 0 deletions lib/std/os/linux/bpf/helpers.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("../../../std.zig");
const kern = @import("kern.zig");

Expand Down
11 changes: 11 additions & 0 deletions lib/std/zig/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ mode: Mode = .zig,

errors: []const Error,

/// If `thisfileisautotranslatedfromc` is present at the top of the file.
is_autotranslated: bool = false,

pub const TokenIndex = u32;
pub const ByteOffset = u32;

Expand Down Expand Up @@ -78,6 +81,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
.extra_data = .{},
.scratch = .{},
.tok_i = 0,
.is_autotranslated = false,
};
defer parser.errors.deinit(gpa);
defer parser.nodes.deinit(gpa);
Expand All @@ -102,6 +106,7 @@ pub fn parse(gpa: Allocator, source: [:0]const u8, mode: Mode) Allocator.Error!A
.nodes = parser.nodes.toOwnedSlice(),
.extra_data = try parser.extra_data.toOwnedSlice(gpa),
.errors = try parser.errors.toOwnedSlice(gpa),
.is_autotranslated = parser.is_autotranslated,
};
}

Expand Down Expand Up @@ -465,6 +470,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
}),
}
},

.autotranslated_not_first_token => {
return stream.writeAll("thisfileisautotranslatedfromc must be the first token in the file");
},
}
}

Expand Down Expand Up @@ -2919,6 +2928,8 @@ pub const Error = struct {

/// `expected_tag` is populated.
expected_token,

autotranslated_not_first_token,
};
};

Expand Down
22 changes: 22 additions & 0 deletions lib/std/zig/Parse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ errors: std.ArrayListUnmanaged(AstError),
nodes: Ast.NodeList,
extra_data: std.ArrayListUnmanaged(Node.Index),
scratch: std.ArrayListUnmanaged(Node.Index),
is_autotranslated: bool,

const SmallSpan = union(enum) {
zero_or_one: Node.Index,
Expand Down Expand Up @@ -368,6 +369,27 @@ fn parseContainerMembers(p: *Parse) !Members {
}
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.keyword_autotranslated => {
const token = p.assertToken(.keyword_autotranslated);
p.expectSemicolon(.expected_semi_after_decl, false) catch |err| {
switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => continue,
}
};

if (p.nodes.len != 1) {
try p.warnMsg(.{
.tag = .autotranslated_not_first_token,
.token = token,
});
continue;
}

p.is_autotranslated = true;

trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.eof, .r_brace => {
if (doc_comment) |tok| {
try p.warnMsg(.{
Expand Down
2 changes: 2 additions & 0 deletions lib/std/zig/c_builtins.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");

pub inline fn __builtin_bswap16(val: u16) u16 {
Expand Down
2 changes: 2 additions & 0 deletions lib/std/zig/c_translation.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const testing = std.testing;
Expand Down
16 changes: 16 additions & 0 deletions lib/std/zig/render.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!v
try renderContainerDocComments(&r, 0);
}

if (tree.is_autotranslated) {
// The token can either be index 0 or 1, depending on whether there's a doc
// comment before hand.
// There should be blank line between the space and the next thing.
// It emphasises the tokens presence.
if (tree.tokens.items(.tag)[0] == .container_doc_comment) {
try renderToken(&r, 1, .semicolon);
} else {
try renderToken(&r, 0, .semicolon);
}

try r.ais.insertNewline();
}

if (tree.mode == .zon) {
try renderExpression(
&r,
Expand All @@ -122,7 +136,9 @@ fn renderMembers(r: *Render, members: []const Ast.Node.Index) Error!void {
const container: Container = for (members) |member| {
if (tree.fullContainerField(member)) |field| if (!field.ast.tuple_like) break .other;
} else .tuple;

try renderMember(r, container, members[0], .newline);

for (members[1..]) |member| {
try renderExtraNewline(r, member);
try renderMember(r, container, member, .newline);
Expand Down
3 changes: 3 additions & 0 deletions lib/std/zig/tokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub const Token = struct {
.{ "var", .keyword_var },
.{ "volatile", .keyword_volatile },
.{ "while", .keyword_while },
.{ "thisfileisautotranslatedfromc", .keyword_autotranslated },
});

pub fn getKeyword(bytes: []const u8) ?Tag {
Expand Down Expand Up @@ -188,6 +189,7 @@ pub const Token = struct {
keyword_var,
keyword_volatile,
keyword_while,
keyword_autotranslated,

pub fn lexeme(tag: Tag) ?[]const u8 {
return switch (tag) {
Expand Down Expand Up @@ -315,6 +317,7 @@ pub const Token = struct {
.keyword_var => "var",
.keyword_volatile => "volatile",
.keyword_while => "while",
.keyword_autotranslated => "thisfileisautotranslatedfromc",
};
}

Expand Down
48 changes: 32 additions & 16 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -410,22 +410,23 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
switch (node_tags[node]) {
.root => unreachable,
.@"usingnamespace" => unreachable,
.test_decl => unreachable,
.global_var_decl => unreachable,
.local_var_decl => unreachable,
.simple_var_decl => unreachable,
.aligned_var_decl => unreachable,
.switch_case => unreachable,
.switch_case_inline => unreachable,
.switch_case_one => unreachable,
.switch_case_inline_one => unreachable,
.container_field_init => unreachable,
.container_field_align => unreachable,
.container_field => unreachable,
.asm_output => unreachable,
.asm_input => unreachable,
.root,
.@"usingnamespace",
.test_decl,
.global_var_decl,
.local_var_decl,
.simple_var_decl,
.aligned_var_decl,
.switch_case,
.switch_case_inline,
.switch_case_one,
.switch_case_inline_one,
.container_field_init,
.container_field_align,
.container_field,
.asm_output,
.asm_input,
=> unreachable,

.assign,
.assign_destructure,
Expand Down Expand Up @@ -3725,6 +3726,21 @@ fn ptrType(
return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{});
}

if (ptr_info.size == .C and !gz.astgen.tree.is_autotranslated) {
return gz.astgen.failNodeNotes(
node,
"[*c] pointers are only allowed in auto-translated C code",
.{},
&[_]u32{
try gz.astgen.errNoteNode(
node,
"* and [*] pointers may be used where a [*c] pointer is expected",
.{},
),
},
);
}

const source_offset = gz.astgen.source_offset;
const source_line = gz.astgen.source_line;
const source_column = gz.astgen.source_column;
Expand Down
2 changes: 1 addition & 1 deletion src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4322,7 +4322,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
const formatted = try tree.render(comp.gpa);
defer comp.gpa.free(formatted);

try out_zig_file.writeAll(formatted);
try out_zig_file.writer().print("thisfileisautotranslatedfromc;\n{s}", .{formatted});

break :digest digest;
} else man.final();
Expand Down
1 change: 1 addition & 0 deletions src/autodoc/render_source.zig
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ pub fn tokenizeAndPrintRaw(
.keyword_allowzero,
.keyword_while,
.keyword_anytype,
.keyword_autotranslated,
=> {
try out.writeAll("<span class=\"tok-kw\">");
try writeEscaped(out, src[token.loc.start..token.loc.end]);
Expand Down
2 changes: 1 addition & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4416,7 +4416,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
const formatted = try tree.render(comp.gpa);
defer comp.gpa.free(formatted);

try zig_file.writeAll(formatted);
try zig_file.writer().print("thisfileisautotranslatedfromc;\n{s}", .{formatted});

man.writeManifest() catch |err| warn("failed to write cache manifest: {s}", .{
@errorName(err),
Expand Down
Binary file modified stage1/zig1.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions test/behavior/bugs/11995.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const testing = std.testing;
const builtin = @import("builtin");
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/bugs/4328.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const expect = @import("std").testing.expect;
const builtin = @import("builtin");

Expand Down
2 changes: 2 additions & 0 deletions test/behavior/cast.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const builtin = @import("builtin");
const std = @import("std");
const assert = std.debug.assert;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/comptime_memory.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const endian = builtin.cpu.arch.endian();
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/generics.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const testing = std.testing;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/optional.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const builtin = @import("builtin");
const std = @import("std");
const testing = std.testing;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/pointers.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const builtin = @import("builtin");
const std = @import("std");
const testing = std.testing;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/slice.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/slice_sentinel_comptime.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

test "comptime slice-sentinel in bounds (unterminated)" {
// array
comptime {
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/threadlocal.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/type.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const Type = std.builtin.Type;
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/type_info.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const std = @import("std");
const builtin = @import("builtin");
const mem = std.mem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

const Foo = struct { a: u32 };
export fn a() void {
const T = [*c]Foo;
Expand All @@ -9,6 +11,6 @@ export fn a() void {
// backend=stage2
// target=native
//
// :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo'
// :3:19: note: only extern structs and ABI sized packed structs are extern compatible
// :1:13: note: struct declared here
// :5:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo'
// :5:19: note: only extern structs and ABI sized packed structs are extern compatible
// :3:13: note: struct declared here
4 changes: 3 additions & 1 deletion test/cases/compile_errors/C_pointer_to_anyopaque.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
thisfileisautotranslatedfromc;

export fn a() void {
var x: *anyopaque = undefined;
var y: [*c]anyopaque = x;
Expand All @@ -8,4 +10,4 @@ export fn a() void {
// backend=stage2
// target=native
//
// :3:16: error: C pointers cannot point to opaque types
// :5:16: error: C pointers cannot point to opaque types
12 changes: 12 additions & 0 deletions test/cases/compile_errors/autotranslated_not_first_token.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export fn a() void {
const foo: [*c]u8 = undefined;
_ = foo;
}

thisfileisautotranslatedfromc;

// error
// backend=stage2
// target=native
//
// :6:1: error: thisfileisautotranslatedfromc must be the first token in the file
Loading