Skip to content

Commit f0ddc7f

Browse files
committed
translate-c: update for new function pointer semantics
After #10656, function pointers are represented with e.g. `*const fn()void` rather than `fn()void`. This commit adds code to translate-c to emit different code depending on whether the output zig source code is intended to be compiled with stage1 or stage2. Ideally we will have stage1 and stage2 support the exact same Zig language, but for now they diverge because I would rather focus on finishing and shipping stage2 than implementing the features in stage1.
1 parent 618055d commit f0ddc7f

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

src/Compilation.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3305,7 +3305,10 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
33053305
var man = comp.obtainCObjectCacheManifest();
33063306
defer man.deinit();
33073307

3308+
const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;
3309+
33083310
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
3311+
man.hash.add(use_stage1);
33093312
man.hash.addBytes(c_src);
33103313

33113314
// If the previous invocation resulted in clang errors, we will see a hit
@@ -3369,6 +3372,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
33693372
new_argv.ptr + new_argv.len,
33703373
&clang_errors,
33713374
c_headers_dir_path_z,
3375+
use_stage1,
33723376
) catch |err| switch (err) {
33733377
error.OutOfMemory => return error.OutOfMemory,
33743378
error.ASTUnitFailure => {

src/main.zig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,7 +2601,8 @@ fn buildOutputType(
26012601
return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
26022602
}
26032603
if (arg_mode == .translate_c) {
2604-
return cmdTranslateC(comp, arena, have_enable_cache);
2604+
const stage1_mode = use_stage1 orelse build_options.is_stage1;
2605+
return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode);
26052606
}
26062607

26072608
const hook: AfterUpdateHook = blk: {
@@ -2997,7 +2998,7 @@ fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void {
29972998
}
29982999
}
29993000

3000-
fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void {
3001+
fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage1_mode: bool) !void {
30013002
if (!build_options.have_llvm)
30023003
fatal("cannot translate-c: compiler built without LLVM extensions", .{});
30033004

@@ -3010,6 +3011,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
30103011
defer if (enable_cache) man.deinit();
30113012

30123013
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
3014+
man.hash.add(stage1_mode);
30133015
man.hashCSource(c_source_file) catch |err| {
30143016
fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
30153017
};
@@ -3061,6 +3063,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
30613063
new_argv.ptr + new_argv.len,
30623064
&clang_errors,
30633065
c_headers_dir_path_z,
3066+
stage1_mode,
30643067
) catch |err| switch (err) {
30653068
error.OutOfMemory => return error.OutOfMemory,
30663069
error.ASTUnitFailure => fatal("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}),

src/translate_c.zig

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,16 @@ pub const Context = struct {
328328

329329
pattern_list: PatternList,
330330

331+
/// This is used to emit different code depending on whether
332+
/// the output zig source code is intended to be compiled with stage1 or stage2.
333+
/// Ideally we will have stage1 and stage2 support the exact same Zig language,
334+
/// but for now they diverge because I would rather focus on finishing and shipping
335+
/// stage2 than implementing the features in stage1.
336+
/// The list of differences are currently:
337+
/// * function pointers in stage1 are e.g. `fn()void`
338+
/// but in stage2 they are `*const fn()void`.
339+
zig_is_stage1: bool,
340+
331341
fn getMangle(c: *Context) u32 {
332342
c.mangle_count += 1;
333343
return c.mangle_count;
@@ -356,6 +366,7 @@ pub fn translate(
356366
args_end: [*]?[*]const u8,
357367
errors: *[]ClangErrMsg,
358368
resources_path: [*:0]const u8,
369+
zig_is_stage1: bool,
359370
) !std.zig.Ast {
360371
const ast_unit = clang.LoadFromCommandLine(
361372
args_begin,
@@ -383,6 +394,7 @@ pub fn translate(
383394
.global_scope = try arena_allocator.create(Scope.Root),
384395
.clang_context = ast_unit.getASTContext(),
385396
.pattern_list = try PatternList.init(gpa),
397+
.zig_is_stage1 = zig_is_stage1,
386398
};
387399
context.global_scope.* = Scope.Root.init(&context);
388400
defer {
@@ -3630,7 +3642,7 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
36303642
else
36313643
return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
36323644
.AddrOf => {
3633-
if (cIsFunctionDeclRef(op_expr)) {
3645+
if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) {
36343646
return transExpr(c, scope, op_expr, used);
36353647
}
36363648
return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
@@ -4656,18 +4668,27 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan
46564668
},
46574669
.Pointer => {
46584670
const child_qt = ty.getPointeeType();
4659-
if (qualTypeChildIsFnProto(child_qt)) {
4671+
const is_fn_proto = qualTypeChildIsFnProto(child_qt);
4672+
if (c.zig_is_stage1 and is_fn_proto) {
46604673
return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));
46614674
}
4662-
const is_const = child_qt.isConstQualified();
4675+
const is_const = is_fn_proto or child_qt.isConstQualified();
46634676
const is_volatile = child_qt.isVolatileQualified();
46644677
const elem_type = try transQualType(c, scope, child_qt, source_loc);
4665-
if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) {
4666-
const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
4678+
const ptr_info = .{
4679+
.is_const = is_const,
4680+
.is_volatile = is_volatile,
4681+
.elem_type = elem_type,
4682+
};
4683+
if (is_fn_proto or
4684+
typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or
4685+
qualTypeWasDemotedToOpaque(c, child_qt))
4686+
{
4687+
const ptr = try Tag.single_pointer.create(c.arena, ptr_info);
46674688
return Tag.optional_type.create(c.arena, ptr);
46684689
}
46694690

4670-
return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
4691+
return Tag.c_pointer.create(c.arena, ptr_info);
46714692
},
46724693
.ConstantArray => {
46734694
const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
@@ -6517,8 +6538,16 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
65176538
return null;
65186539
if (getContainerTypeOf(c, init)) |ty_node| {
65196540
if (ty_node.castTag(.optional_type)) |prefix| {
6520-
if (prefix.data.castTag(.func)) |fn_proto| {
6521-
return fn_proto;
6541+
if (c.zig_is_stage1) {
6542+
if (prefix.data.castTag(.func)) |fn_proto| {
6543+
return fn_proto;
6544+
}
6545+
} else {
6546+
if (prefix.data.castTag(.single_pointer)) |sp| {
6547+
if (sp.data.elem_type.castTag(.func)) |fn_proto| {
6548+
return fn_proto;
6549+
}
6550+
}
65226551
}
65236552
}
65246553
}

0 commit comments

Comments
 (0)