authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-25 22:01:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-25 22:04:01-07:00
logf0ddc7f7a2e2fba2515dfb4f3ad06ea56646eba7
tree45f70c9e463de4113c1ac64ba689582736a260b9
parent618055db50c5354a17f9eefc2cee77ec2de96f6a

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.

3 files changed, 46 insertions(+), 10 deletions(-)

src/Compilation.zig+4
...@@ -3305,7 +3305,10 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {...@@ -3305,7 +3305,10 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
3305 var man = comp.obtainCObjectCacheManifest();3305 var man = comp.obtainCObjectCacheManifest();
3306 defer man.deinit();3306 defer man.deinit();
33073307
3308 const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;
3309
3308 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects3310 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
3311 man.hash.add(use_stage1);
3309 man.hash.addBytes(c_src);3312 man.hash.addBytes(c_src);
33103313
3311 // If the previous invocation resulted in clang errors, we will see a hit3314 // 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 {...@@ -3369,6 +3372,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
3369 new_argv.ptr + new_argv.len,3372 new_argv.ptr + new_argv.len,
3370 &clang_errors,3373 &clang_errors,
3371 c_headers_dir_path_z,3374 c_headers_dir_path_z,
3375 use_stage1,
3372 ) catch |err| switch (err) {3376 ) catch |err| switch (err) {
3373 error.OutOfMemory => return error.OutOfMemory,3377 error.OutOfMemory => return error.OutOfMemory,
3374 error.ASTUnitFailure => {3378 error.ASTUnitFailure => {
src/main.zig+5-2
...@@ -2601,7 +2601,8 @@ fn buildOutputType(...@@ -2601,7 +2601,8 @@ fn buildOutputType(
2601 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));2601 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
2602 }2602 }
2603 if (arg_mode == .translate_c) {2603 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);
2605 }2606 }
26062607
2607 const hook: AfterUpdateHook = blk: {2608 const hook: AfterUpdateHook = blk: {
...@@ -2997,7 +2998,7 @@ fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void {...@@ -2997,7 +2998,7 @@ fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void {
2997 }2998 }
2998}2999}
29993000
3000fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void {3001fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage1_mode: bool) !void {
3001 if (!build_options.have_llvm)3002 if (!build_options.have_llvm)
3002 fatal("cannot translate-c: compiler built without LLVM extensions", .{});3003 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
30033004
...@@ -3010,6 +3011,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void...@@ -3010,6 +3011,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
3010 defer if (enable_cache) man.deinit();3011 defer if (enable_cache) man.deinit();
30113012
3012 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects3013 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
3014 man.hash.add(stage1_mode);
3013 man.hashCSource(c_source_file) catch |err| {3015 man.hashCSource(c_source_file) catch |err| {
3014 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });3016 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
3015 };3017 };
...@@ -3061,6 +3063,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void...@@ -3061,6 +3063,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
3061 new_argv.ptr + new_argv.len,3063 new_argv.ptr + new_argv.len,
3062 &clang_errors,3064 &clang_errors,
3063 c_headers_dir_path_z,3065 c_headers_dir_path_z,
3066 stage1_mode,
3064 ) catch |err| switch (err) {3067 ) catch |err| switch (err) {
3065 error.OutOfMemory => return error.OutOfMemory,3068 error.OutOfMemory => return error.OutOfMemory,
3066 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", .{}),3069 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+37-8
...@@ -328,6 +328,16 @@ pub const Context = struct {...@@ -328,6 +328,16 @@ pub const Context = struct {
328328
329 pattern_list: PatternList,329 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
331 fn getMangle(c: *Context) u32 {341 fn getMangle(c: *Context) u32 {
332 c.mangle_count += 1;342 c.mangle_count += 1;
333 return c.mangle_count;343 return c.mangle_count;
...@@ -356,6 +366,7 @@ pub fn translate(...@@ -356,6 +366,7 @@ pub fn translate(
356 args_end: [*]?[*]const u8,366 args_end: [*]?[*]const u8,
357 errors: *[]ClangErrMsg,367 errors: *[]ClangErrMsg,
358 resources_path: [*:0]const u8,368 resources_path: [*:0]const u8,
369 zig_is_stage1: bool,
359) !std.zig.Ast {370) !std.zig.Ast {
360 const ast_unit = clang.LoadFromCommandLine(371 const ast_unit = clang.LoadFromCommandLine(
361 args_begin,372 args_begin,
...@@ -383,6 +394,7 @@ pub fn translate(...@@ -383,6 +394,7 @@ pub fn translate(
383 .global_scope = try arena_allocator.create(Scope.Root),394 .global_scope = try arena_allocator.create(Scope.Root),
384 .clang_context = ast_unit.getASTContext(),395 .clang_context = ast_unit.getASTContext(),
385 .pattern_list = try PatternList.init(gpa),396 .pattern_list = try PatternList.init(gpa),
397 .zig_is_stage1 = zig_is_stage1,
386 };398 };
387 context.global_scope.* = Scope.Root.init(&context);399 context.global_scope.* = Scope.Root.init(&context);
388 defer {400 defer {
...@@ -3630,7 +3642,7 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat...@@ -3630,7 +3642,7 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
3630 else3642 else
3631 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),3643 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
3632 .AddrOf => {3644 .AddrOf => {
3633 if (cIsFunctionDeclRef(op_expr)) {3645 if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) {
3634 return transExpr(c, scope, op_expr, used);3646 return transExpr(c, scope, op_expr, used);
3635 }3647 }
3636 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));3648 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...@@ -4656,18 +4668,27 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan
4656 },4668 },
4657 .Pointer => {4669 .Pointer => {
4658 const child_qt = ty.getPointeeType();4670 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) {
4660 return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));4673 return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));
4661 }4674 }
4662 const is_const = child_qt.isConstQualified();4675 const is_const = is_fn_proto or child_qt.isConstQualified();
4663 const is_volatile = child_qt.isVolatileQualified();4676 const is_volatile = child_qt.isVolatileQualified();
4664 const elem_type = try transQualType(c, scope, child_qt, source_loc);4677 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)) {4678 const ptr_info = .{
4666 const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });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);
4667 return Tag.optional_type.create(c.arena, ptr);4688 return Tag.optional_type.create(c.arena, ptr);
4668 }4689 }
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);
4671 },4692 },
4672 .ConstantArray => {4693 .ConstantArray => {
4673 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);4694 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
...@@ -6517,8 +6538,16 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {...@@ -6517,8 +6538,16 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
6517 return null;6538 return null;
6518 if (getContainerTypeOf(c, init)) |ty_node| {6539 if (getContainerTypeOf(c, init)) |ty_node| {
6519 if (ty_node.castTag(.optional_type)) |prefix| {6540 if (ty_node.castTag(.optional_type)) |prefix| {
6520 if (prefix.data.castTag(.func)) |fn_proto| {6541 if (c.zig_is_stage1) {
6521 return fn_proto;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 }
6522 }6551 }
6523 }6552 }
6524 }6553 }