diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Cache.zig | 2 | ||||
| -rw-r--r-- | src/Compilation.zig | 6 | ||||
| -rw-r--r-- | src/Module.zig | 37 | ||||
| -rw-r--r-- | src/clang.zig | 5 | ||||
| -rw-r--r-- | src/clang_options_data.zig | 9 | ||||
| -rw-r--r-- | src/codegen.zig | 106 | ||||
| -rw-r--r-- | src/codegen/arm.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO.zig | 2 | ||||
| -rw-r--r-- | src/main.zig | 7 | ||||
| -rw-r--r-- | src/musl.zig | 14 | ||||
| -rw-r--r-- | src/stage1.zig | 4 | ||||
| -rw-r--r-- | src/stage1/all_types.hpp | 12 | ||||
| -rw-r--r-- | src/stage1/analyze.cpp | 20 | ||||
| -rw-r--r-- | src/stage1/ast_render.cpp | 11 | ||||
| -rw-r--r-- | src/stage1/codegen.cpp | 46 | ||||
| -rw-r--r-- | src/stage1/ir.cpp | 23 | ||||
| -rw-r--r-- | src/stage1/parser.cpp | 17 | ||||
| -rw-r--r-- | src/tracy.zig | 2 | ||||
| -rw-r--r-- | src/translate_c.zig | 149 | ||||
| -rw-r--r-- | src/type.zig | 4 | ||||
| -rw-r--r-- | src/zig_clang.cpp | 5 | ||||
| -rw-r--r-- | src/zig_clang.h | 2 | ||||
| -rw-r--r-- | src/zir.zig | 9 | ||||
| -rw-r--r-- | src/zir_sema.zig | 34 |
24 files changed, 302 insertions, 226 deletions
diff --git a/src/Cache.zig b/src/Cache.zig index f5ffb34dbe..57ff9227fa 100644 --- a/src/Cache.zig +++ b/src/Cache.zig @@ -317,7 +317,7 @@ pub const Manifest = struct { cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat; cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; - std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; + _ = std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; if (file_path.len == 0) { return error.InvalidFormat; diff --git a/src/Compilation.zig b/src/Compilation.zig index c7bb260aa7..180d49a196 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -645,7 +645,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { }; const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: { - const opts: DarwinOptions = if (use_lld and options.is_native_os and options.target.isDarwin()) inner: { + const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: { // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. // See https://github.com/ziglang/zig/issues/6996 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; @@ -1538,7 +1538,9 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 { } pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void { - var progress: std.Progress = .{}; + // If the terminal is dumb, we dont want to show the user all the + // output. + var progress: std.Progress = .{ .dont_print_on_dumb = true }; var main_progress_node = try progress.start("", 0); defer main_progress_node.end(); if (self.color == .off) progress.terminal = null; diff --git a/src/Module.zig b/src/Module.zig index 8de03b54ab..322f190673 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1087,14 +1087,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { if (fn_proto.getSectionExpr()) |sect_expr| { return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{}); } - if (fn_proto.getCallconvExpr()) |callconv_expr| { - return self.failNode( - &fn_type_scope.base, - callconv_expr, - "TODO implement function calling convention expression", - .{}, - ); - } + + const enum_literal_type = try astgen.addZIRInstConst(self, &fn_type_scope.base, fn_src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.enum_literal_type), + }); + const enum_literal_type_rl: astgen.ResultLoc = .{ .ty = enum_literal_type }; + const cc = if (fn_proto.getCallconvExpr()) |callconv_expr| + try astgen.expr(self, &fn_type_scope.base, enum_literal_type_rl, callconv_expr) + else + try astgen.addZIRInstConst(self, &fn_type_scope.base, fn_src, .{ + .ty = Type.initTag(.enum_literal), + .val = try Value.Tag.enum_literal.create( + &fn_type_scope_arena.allocator, + try fn_type_scope_arena.allocator.dupe(u8, "Unspecified"), + ), + }); + const return_type_expr = switch (fn_proto.return_type) { .Explicit => |node| node, .InferErrorSet => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement inferred error sets", .{}), @@ -1105,6 +1114,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const fn_type_inst = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{ .return_type = return_type_inst, .param_types = param_types, + .cc = cc, }, .{}); if (std.builtin.mode == .Debug and self.comp.verbose_ir) { @@ -1230,14 +1240,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; }; - const is_inline = blk: { - if (fn_proto.getExternExportInlineToken()) |maybe_inline_token| { - if (tree.token_ids[maybe_inline_token] == .Keyword_inline) { - break :blk true; - } - } - break :blk false; - }; + const is_inline = fn_type.fnCallingConvention() == .Inline; const anal_state = ([2]Fn.Analysis{ .queued, .inline_only })[@boolToInt(is_inline)]; new_func.* = .{ @@ -2400,7 +2403,7 @@ fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIn else => unreachable, }; const loc = tree.tokenLocationLoc(0, tree.token_locs[base_token]); - return std.fmt.allocPrint(self.gpa, "{}:{}:{}", .{ base_name, loc.line, loc.column }); + return std.fmt.allocPrint(self.gpa, "{s}:{}:{}", .{ base_name, loc.line, loc.column }); } fn getNextAnonNameIndex(self: *Module) usize { diff --git a/src/clang.zig b/src/clang.zig index fc7a25fe12..954cfee6b2 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -848,7 +848,10 @@ pub const UnaryOperator = opaque { extern fn ZigClangUnaryOperator_getBeginLoc(*const UnaryOperator) SourceLocation; }; -pub const ValueDecl = opaque {}; +pub const ValueDecl = opaque { + pub const getType = ZigClangValueDecl_getType; + extern fn ZigClangValueDecl_getType(*const ValueDecl) QualType; +}; pub const VarDecl = opaque { pub const getLocation = ZigClangVarDecl_getLocation; diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 4d89308545..0293a5327e 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -4305,7 +4305,14 @@ flagpd1("rewrite-macros"), flagpd1("rewrite-objc"), flagpd1("rewrite-test"), sepd1("rpath"), -flagpd1("s"), +.{ + .name = "s", + .syntax = .flag, + .zig_equivalent = .strip, + .pd1 = true, + .pd2 = false, + .psl = false, +}, .{ .name = "save-stats", .syntax = .flag, diff --git a/src/codegen.zig b/src/codegen.zig index 904fda0deb..d81ad1faf5 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1295,38 +1295,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const rhs = try self.resolveInst(op_rhs); // Destination must be a register - // Source may be register, memory or an immediate - // - // So there are two options: (lhs is src and rhs is dest) - // or (rhs is src and lhs is dest) - const lhs_is_dest = blk: { - if (self.reuseOperand(inst, 0, lhs)) { - break :blk true; - } else if (self.reuseOperand(inst, 1, rhs)) { - break :blk false; - } else { - break :blk lhs == .register; - } - }; - var dst_mcv: MCValue = undefined; - var src_mcv: MCValue = undefined; - var src_inst: *ir.Inst = undefined; - if (lhs_is_dest) { + var lhs_mcv: MCValue = undefined; + var rhs_mcv: MCValue = undefined; + if (self.reuseOperand(inst, 0, lhs)) { // LHS is the destination // RHS is the source - src_inst = op_rhs; - src_mcv = rhs; - dst_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs; - } else { + lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs; + rhs_mcv = rhs; + dst_mcv = lhs_mcv; + } else if (self.reuseOperand(inst, 1, rhs)) { // RHS is the destination // LHS is the source - src_inst = op_lhs; - src_mcv = lhs; - dst_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs; + lhs_mcv = lhs; + rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs; + dst_mcv = rhs_mcv; + } else { + // TODO save 1 copy instruction by directly allocating the destination register + // LHS is the destination + // RHS is the source + lhs_mcv = try self.copyToNewRegister(inst, lhs); + rhs_mcv = rhs; + dst_mcv = lhs_mcv; } - try self.genArmBinOpCode(inst.src, dst_mcv.register, src_mcv, lhs_is_dest, op); + try self.genArmBinOpCode(inst.src, dst_mcv.register, lhs_mcv, rhs_mcv, op); return dst_mcv; } @@ -1334,11 +1327,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { self: *Self, src: usize, dst_reg: Register, - src_mcv: MCValue, - lhs_is_dest: bool, + lhs_mcv: MCValue, + rhs_mcv: MCValue, op: ir.Inst.Tag, ) !void { - const operand = switch (src_mcv) { + assert(lhs_mcv == .register or lhs_mcv == .register); + + const swap_lhs_and_rhs = rhs_mcv == .register and lhs_mcv != .register; + const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register; + const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv; + + const operand = switch (op2) { .none => unreachable, .undef => unreachable, .dead, .unreach => unreachable, @@ -1352,37 +1351,37 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { // Load immediate into register if it doesn't fit // as an operand break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse - Instruction.Operand.reg(try self.copyToTmpRegister(src, src_mcv), Instruction.Operand.Shift.none); + Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none); }, - .register => |src_reg| Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none), + .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), .stack_offset, .embedded_in_code, .memory, - => Instruction.Operand.reg(try self.copyToTmpRegister(src, src_mcv), Instruction.Operand.Shift.none), + => Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none), }; switch (op) { .add => { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.add(.al, dst_reg, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.add(.al, dst_reg, op1, operand).toU32()); }, .sub => { - if (lhs_is_dest) { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.sub(.al, dst_reg, dst_reg, operand).toU32()); + if (swap_lhs_and_rhs) { + writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, op1, operand).toU32()); } else { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.rsb(.al, dst_reg, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.sub(.al, dst_reg, op1, operand).toU32()); } }, .bool_and, .bit_and => { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.@"and"(.al, dst_reg, op1, operand).toU32()); }, .bool_or, .bit_or => { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, dst_reg, op1, operand).toU32()); }, .not, .xor => { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.eor(.al, dst_reg, op1, operand).toU32()); }, .cmp_eq => { - writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, dst_reg, operand).toU32()); + writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, op1, operand).toU32()); }, else => unreachable, // not a binary instruction } @@ -2135,7 +2134,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const src_mcv = rhs; const dst_mcv = if (lhs != .register) try self.copyToNewRegister(&inst.base, lhs) else lhs; - try self.genArmBinOpCode(inst.base.src, dst_mcv.register, src_mcv, true, .cmp_eq); + try self.genArmBinOpCode(inst.base.src, dst_mcv.register, dst_mcv, src_mcv, .cmp_eq); const info = inst.lhs.ty.intInfo(self.target.*); return switch (info.signedness) { .signed => MCValue{ .compare_flags_signed = op }, @@ -2224,7 +2223,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { writeInt(u32, try self.code.addManyAsArray(4), Instruction.cmp(.al, reg, op).toU32()); break :blk .ne; }, - else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {}", .{ self.target.cpu.arch, @tagName(cond) }), + else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }), }; const reloc = Reloc{ @@ -3706,17 +3705,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { for (param_types) |ty, i| { switch (ty.zigTypeTag()) { .Bool, .Int => { - const param_size = @intCast(u32, ty.abiSize(self.target.*)); - if (next_int_reg >= c_abi_int_param_regs.len) { - result.args[i] = .{ .stack_offset = next_stack_offset }; - next_stack_offset += param_size; + if (!ty.hasCodeGenBits()) { + assert(cc != .C); + result.args[i] = .{ .none = {} }; } else { - const aliased_reg = registerAlias( - c_abi_int_param_regs[next_int_reg], - param_size, - ); - result.args[i] = .{ .register = aliased_reg }; - next_int_reg += 1; + const param_size = @intCast(u32, ty.abiSize(self.target.*)); + if (next_int_reg >= c_abi_int_param_regs.len) { + result.args[i] = .{ .stack_offset = next_stack_offset }; + next_stack_offset += param_size; + } else { + const aliased_reg = registerAlias( + c_abi_int_param_regs[next_int_reg], + param_size, + ); + result.args[i] = .{ .register = aliased_reg }; + next_int_reg += 1; + } } }, else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}), diff --git a/src/codegen/arm.zig b/src/codegen/arm.zig index 94f1ae951d..d538d28c50 100644 --- a/src/codegen/arm.zig +++ b/src/codegen/arm.zig @@ -186,7 +186,7 @@ pub const Psr = enum { spsr, }; -pub const callee_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3, .r4, .r5, .r6, .r7, .r8, .r10 }; +pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 }; pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 }; pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index eee5841903..fd1c53cb67 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2366,7 +2366,7 @@ fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 { return min_pos - start; } -inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 { +fn checkForCollision(start: u64, end: u64, off: u64, size: u64) callconv(.Inline) ?u64 { const increased_size = padToIdeal(size); const test_end = off + increased_size; if (end > off and start < test_end) { diff --git a/src/main.zig b/src/main.zig index bfe0d6786b..c31252a96a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1186,6 +1186,7 @@ fn buildOutputType( .framework_dir => try framework_dirs.append(it.only_arg), .framework => try frameworks.append(it.only_arg), .nostdlibinc => want_native_include_dirs = false, + .strip => strip = true, } } // Parse linker args. @@ -1536,8 +1537,9 @@ fn buildOutputType( } const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: { - const at_least_big_sur = target_info.target.os.getVersionRange().semver.min.major >= 11; - if (at_least_big_sur) { + const min = target_info.target.os.getVersionRange().semver.min; + const at_least_catalina = min.major >= 11 or (min.major >= 10 and min.minor >= 15); + if (at_least_catalina) { const sdk_path = try std.zig.system.getSDKPath(arena); try clang_argv.ensureCapacity(clang_argv.items.len + 2); clang_argv.appendAssumeCapacity("-isysroot"); @@ -3046,6 +3048,7 @@ pub const ClangArgIterator = struct { nostdlibinc, red_zone, no_red_zone, + strip, }; const Args = struct { diff --git a/src/musl.zig b/src/musl.zig index 0cb6983e28..0f0e3b271a 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -522,6 +522,7 @@ const src_files = [_][]const u8{ "musl/src/errno/strerror.c", "musl/src/exit/_Exit.c", "musl/src/exit/abort.c", + "musl/src/exit/abort_lock.c", "musl/src/exit/arm/__aeabi_atexit.c", "musl/src/exit/assert.c", "musl/src/exit/at_quick_exit.c", @@ -658,6 +659,7 @@ const src_files = [_][]const u8{ "musl/src/linux/flock.c", "musl/src/linux/getdents.c", "musl/src/linux/getrandom.c", + "musl/src/linux/gettid.c", "musl/src/linux/inotify.c", "musl/src/linux/ioperm.c", "musl/src/linux/iopl.c", @@ -731,6 +733,8 @@ const src_files = [_][]const u8{ "musl/src/locale/wcscoll.c", "musl/src/locale/wcsxfrm.c", "musl/src/malloc/calloc.c", + "musl/src/malloc/free.c", + "musl/src/malloc/libc_calloc.c", "musl/src/malloc/lite_malloc.c", "musl/src/malloc/mallocng/aligned_alloc.c", "musl/src/malloc/mallocng/donate.c", @@ -739,7 +743,12 @@ const src_files = [_][]const u8{ "musl/src/malloc/mallocng/malloc_usable_size.c", "musl/src/malloc/mallocng/realloc.c", "musl/src/malloc/memalign.c", + "musl/src/malloc/oldmalloc/aligned_alloc.c", + "musl/src/malloc/oldmalloc/malloc.c", + "musl/src/malloc/oldmalloc/malloc_usable_size.c", "musl/src/malloc/posix_memalign.c", + "musl/src/malloc/realloc.c", + "musl/src/malloc/reallocarray.c", "musl/src/malloc/replaced.c", "musl/src/math/__cos.c", "musl/src/math/__cosdf.c", @@ -754,6 +763,7 @@ const src_files = [_][]const u8{ "musl/src/math/__math_divzerof.c", "musl/src/math/__math_invalid.c", "musl/src/math/__math_invalidf.c", + "musl/src/math/__math_invalidl.c", "musl/src/math/__math_oflow.c", "musl/src/math/__math_oflowf.c", "musl/src/math/__math_uflow.c", @@ -1137,6 +1147,7 @@ const src_files = [_][]const u8{ "musl/src/math/sinhl.c", "musl/src/math/sinl.c", "musl/src/math/sqrt.c", + "musl/src/math/sqrt_data.c", "musl/src/math/sqrtf.c", "musl/src/math/sqrtl.c", "musl/src/math/tan.c", @@ -1406,6 +1417,7 @@ const src_files = [_][]const u8{ "musl/src/prng/random.c", "musl/src/prng/seed48.c", "musl/src/prng/srand48.c", + "musl/src/process/_Fork.c", "musl/src/process/arm/vfork.s", "musl/src/process/execl.c", "musl/src/process/execle.c", @@ -1833,8 +1845,10 @@ const src_files = [_][]const u8{ "musl/src/termios/tcflush.c", "musl/src/termios/tcgetattr.c", "musl/src/termios/tcgetsid.c", + "musl/src/termios/tcgetwinsize.c", "musl/src/termios/tcsendbreak.c", "musl/src/termios/tcsetattr.c", + "musl/src/termios/tcsetwinsize.c", "musl/src/thread/__lock.c", "musl/src/thread/__set_thread_area.c", "musl/src/thread/__syscall_cp.c", diff --git a/src/stage1.zig b/src/stage1.zig index 8ab3b1d94d..1b7eadd1a8 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -278,7 +278,9 @@ export fn stage2_attach_segfault_handler() void { // ABI warning export fn stage2_progress_create() *std.Progress { const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory"); - ptr.* = std.Progress{}; + // If the terminal is dumb, we dont want to show the user all the + // output. + ptr.* = std.Progress{ .dont_print_on_dumb = true }; return ptr; } diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index d2741320d7..7ad585a524 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -74,6 +74,7 @@ enum CallingConvention { CallingConventionC, CallingConventionNaked, CallingConventionAsync, + CallingConventionInline, CallingConventionInterrupt, CallingConventionSignal, CallingConventionStdcall, @@ -703,12 +704,6 @@ enum NodeType { NodeTypeAnyTypeField, }; -enum FnInline { - FnInlineAuto, - FnInlineAlways, - FnInlineNever, -}; - struct AstNodeFnProto { Buf *name; ZigList<AstNode *> params; @@ -725,13 +720,12 @@ struct AstNodeFnProto { AstNode *callconv_expr; Buf doc_comments; - FnInline fn_inline; - VisibMod visib_mod; bool auto_err_set; bool is_var_args; bool is_extern; bool is_export; + bool is_noinline; }; struct AstNodeFnDef { @@ -1719,7 +1713,6 @@ struct ZigFn { LLVMValueRef valgrind_client_request_array; - FnInline fn_inline; FnAnalState anal_state; uint32_t align_bytes; @@ -1728,6 +1721,7 @@ struct ZigFn { bool calls_or_awaits_errorable_fn; bool is_cold; bool is_test; + bool is_noinline; }; uint32_t fn_table_entry_hash(ZigFn*); diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index c701abce8a..a4e368288e 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -973,6 +973,7 @@ const char *calling_convention_name(CallingConvention cc) { case CallingConventionAPCS: return "APCS"; case CallingConventionAAPCS: return "AAPCS"; case CallingConventionAAPCSVFP: return "AAPCSVFP"; + case CallingConventionInline: return "Inline"; } zig_unreachable(); } @@ -981,6 +982,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: case CallingConventionAsync: + case CallingConventionInline: return true; case CallingConventionC: case CallingConventionNaked: @@ -1007,7 +1009,8 @@ ZigType *get_stack_trace_type(CodeGen *g) { } bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { - if (fn_type_id->cc == CallingConventionUnspecified) { + if (fn_type_id->cc == CallingConventionUnspecified + || fn_type_id->cc == CallingConventionInline) { return handle_is_ptr(g, fn_type_id->return_type); } if (fn_type_id->cc != CallingConventionC) { @@ -1888,6 +1891,7 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_ case CallingConventionC: case CallingConventionNaked: case CallingConventionAsync: + case CallingConventionInline: break; case CallingConventionInterrupt: if (g->zig_target->arch != ZigLLVM_x86 @@ -3587,7 +3591,7 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i } } -static ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { +static ZigFn *create_fn_raw(CodeGen *g, bool is_noinline) { ZigFn *fn_entry = heap::c_allocator.create<ZigFn>(); fn_entry->ir_executable = heap::c_allocator.create<IrExecutableSrc>(); @@ -3597,7 +3601,7 @@ static ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->ir_executable->fn_entry = fn_entry; - fn_entry->fn_inline = inline_value; + fn_entry->is_noinline = is_noinline; return fn_entry; } @@ -3606,7 +3610,7 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline); + ZigFn *fn_entry = create_fn_raw(g, fn_proto->is_noinline); fn_entry->proto_node = proto_node; fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : @@ -3739,6 +3743,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->type_entry = g->builtin_types.entry_invalid; tld_fn->base.resolution = TldResolutionInvalid; return; + case CallingConventionInline: + add_node_error(g, fn_def_node, + buf_sprintf("exported function cannot be inline")); + fn_table_entry->type_entry = g->builtin_types.entry_invalid; + tld_fn->base.resolution = TldResolutionInvalid; + return; case CallingConventionC: case CallingConventionNaked: case CallingConventionInterrupt: @@ -3774,7 +3784,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->inferred_async_node = fn_table_entry->proto_node; } } else if (source_node->type == NodeTypeTestDecl) { - ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto); + ZigFn *fn_table_entry = create_fn_raw(g, false); get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, true); diff --git a/src/stage1/ast_render.cpp b/src/stage1/ast_render.cpp index e3f9d11404..9aebac1d28 100644 --- a/src/stage1/ast_render.cpp +++ b/src/stage1/ast_render.cpp @@ -123,13 +123,8 @@ static const char *export_string(bool is_export) { // zig_unreachable(); //} -static const char *inline_string(FnInline fn_inline) { - switch (fn_inline) { - case FnInlineAlways: return "inline "; - case FnInlineNever: return "noinline "; - case FnInlineAuto: return ""; - } - zig_unreachable(); +static const char *inline_string(bool is_inline) { + return is_inline ? "inline" : ""; } static const char *const_or_var_string(bool is_const) { @@ -446,7 +441,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *export_str = export_string(node->data.fn_proto.is_export); - const char *inline_str = inline_string(node->data.fn_proto.fn_inline); + const char *inline_str = inline_string(node->data.fn_proto.is_noinline); fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { print_symbol(ar, node->data.fn_proto.name); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 6aa134c3b0..7f8b1884bd 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -159,6 +159,7 @@ static const char *get_mangled_name(CodeGen *g, const char *original_name) { static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: + case CallingConventionInline: return ZigLLVM_Fast; case CallingConventionC: return ZigLLVM_C; @@ -350,6 +351,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { return true; case CallingConventionAsync: case CallingConventionUnspecified: + case CallingConventionInline: return false; } zig_unreachable(); @@ -452,20 +454,11 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { } } - switch (fn->fn_inline) { - case FnInlineAlways: - addLLVMFnAttr(llvm_fn, "alwaysinline"); - g->inline_fns.append(fn); - break; - case FnInlineNever: - addLLVMFnAttr(llvm_fn, "noinline"); - break; - case FnInlineAuto: - if (fn->alignstack_value != 0) { - addLLVMFnAttr(llvm_fn, "noinline"); - } - break; - } + if (cc == CallingConventionInline) + addLLVMFnAttr(llvm_fn, "alwaysinline"); + + if (fn->is_noinline || (cc != CallingConventionInline && fn->alignstack_value != 0)) + addLLVMFnAttr(llvm_fn, "noinline"); if (cc == CallingConventionNaked) { addLLVMFnAttr(llvm_fn, "naked"); @@ -532,7 +525,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { addLLVMFnAttr(llvm_fn, "nounwind"); add_uwtable_attr(g, llvm_fn); addLLVMFnAttr(llvm_fn, "nobuiltin"); - if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) { + if (codegen_have_frame_pointer(g) && cc != CallingConventionInline) { ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all"); } if (fn->section_name) { @@ -9043,19 +9036,16 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { static_assert(CallingConventionC == 1, ""); static_assert(CallingConventionNaked == 2, ""); static_assert(CallingConventionAsync == 3, ""); - static_assert(CallingConventionInterrupt == 4, ""); - static_assert(CallingConventionSignal == 5, ""); - static_assert(CallingConventionStdcall == 6, ""); - static_assert(CallingConventionFastcall == 7, ""); - static_assert(CallingConventionVectorcall == 8, ""); - static_assert(CallingConventionThiscall == 9, ""); - static_assert(CallingConventionAPCS == 10, ""); - static_assert(CallingConventionAAPCS == 11, ""); - static_assert(CallingConventionAAPCSVFP == 12, ""); - - static_assert(FnInlineAuto == 0, ""); - static_assert(FnInlineAlways == 1, ""); - static_assert(FnInlineNever == 2, ""); + static_assert(CallingConventionInline == 4, ""); + static_assert(CallingConventionInterrupt == 5, ""); + static_assert(CallingConventionSignal == 6, ""); + static_assert(CallingConventionStdcall == 7, ""); + static_assert(CallingConventionFastcall == 8, ""); + static_assert(CallingConventionVectorcall == 9, ""); + static_assert(CallingConventionThiscall == 10, ""); + static_assert(CallingConventionAPCS == 11, ""); + static_assert(CallingConventionAAPCS == 12, ""); + static_assert(CallingConventionAAPCSVFP == 13, ""); static_assert(BuiltinPtrSizeOne == 0, ""); static_assert(BuiltinPtrSizeMany == 1, ""); diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index e876873022..7906df3b0d 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -19000,7 +19000,7 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV } else if (init_val->type->id == ZigTypeIdFn && init_val->special != ConstValSpecialUndef && init_val->data.x_ptr.special == ConstPtrSpecialFunction && - init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) + init_val->data.x_ptr.data.fn.fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) { var_class_requires_const = true; if (!var->src_is_const && !is_comptime_var) { @@ -19182,6 +19182,11 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport buf_sprintf("exported function cannot be async")); add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); } break; + case CallingConventionInline: { + ErrorMsg *msg = ir_add_error(ira, &target->base, + buf_sprintf("exported function cannot be inline")); + add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); + } break; case CallingConventionC: case CallingConventionNaked: case CallingConventionInterrupt: @@ -21120,7 +21125,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, if (type_is_invalid(return_type)) return ira->codegen->invalid_inst_gen; - if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && modifier == CallModifierNeverInline) { + if (fn_entry != nullptr && fn_type_id->cc == CallingConventionInline && modifier == CallModifierNeverInline) { ir_add_error(ira, source_instr, buf_sprintf("no-inline call of inline function")); return ira->codegen->invalid_inst_gen; @@ -25219,10 +25224,6 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown))) return err; - ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type); - if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown))) - return err; - resolve_container_usingnamespace_decls(ira->codegen, decls_scope); // The unresolved declarations are collected in a separate queue to avoid @@ -25365,11 +25366,11 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa fn_decl_fields[0]->special = ConstValSpecialStatic; fn_decl_fields[0]->type = ira->codegen->builtin_types.entry_type; fn_decl_fields[0]->data.x_type = fn_entry->type_entry; - // inline_type: Data.FnDecl.Inline - ensure_field_index(fn_decl_val->type, "inline_type", 1); + // is_noinline: bool + ensure_field_index(fn_decl_val->type, "is_noinline", 1); fn_decl_fields[1]->special = ConstValSpecialStatic; - fn_decl_fields[1]->type = type_info_fn_decl_inline_type; - bigint_init_unsigned(&fn_decl_fields[1]->data.x_enum_tag, fn_entry->fn_inline); + fn_decl_fields[1]->type = ira->codegen->builtin_types.entry_bool; + fn_decl_fields[1]->data.x_bool = fn_entry->is_noinline; // is_var_args: bool ensure_field_index(fn_decl_val->type, "is_var_args", 2); bool is_varargs = fn_node->is_var_args; @@ -30957,7 +30958,7 @@ static IrInstGen *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstS return ira->codegen->invalid_inst_gen; } - if (fn_entry->fn_inline == FnInlineAlways) { + if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) { ir_add_error(ira, &instruction->base.base, buf_sprintf("@setAlignStack in inline function")); return ira->codegen->invalid_inst_gen; } diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp index 3fe85adbf5..c37b3ffefb 100644 --- a/src/stage1/parser.cpp +++ b/src/stage1/parser.cpp @@ -694,15 +694,13 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordExtern); if (first == nullptr) - first = eat_token_if(pc, TokenIdKeywordInline); - if (first == nullptr) first = eat_token_if(pc, TokenIdKeywordNoInline); if (first != nullptr) { Token *lib_name = nullptr; if (first->id == TokenIdKeywordExtern) lib_name = eat_token_if(pc, TokenIdStringLiteral); - if (first->id != TokenIdKeywordInline && first->id != TokenIdKeywordNoInline) { + if (first->id != TokenIdKeywordNoInline) { Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { @@ -739,17 +737,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B if (!fn_proto->data.fn_proto.is_extern) fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; - switch (first->id) { - case TokenIdKeywordInline: - fn_proto->data.fn_proto.fn_inline = FnInlineAlways; - break; - case TokenIdKeywordNoInline: - fn_proto->data.fn_proto.fn_inline = FnInlineNever; - break; - default: - fn_proto->data.fn_proto.fn_inline = FnInlineAuto; - break; - } + if (first->id == TokenIdKeywordNoInline) + fn_proto->data.fn_proto.is_noinline = true; fn_proto->data.fn_proto.lib_name = token_buf(lib_name); AstNode *res = fn_proto; diff --git a/src/tracy.zig b/src/tracy.zig index 6f56a87ce6..3f6cf56588 100644 --- a/src/tracy.zig +++ b/src/tracy.zig @@ -31,7 +31,7 @@ pub const Ctx = if (enable) ___tracy_c_zone_context else struct { pub fn end(self: Ctx) void {} }; -pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx { +pub fn trace(comptime src: std.builtin.SourceLocation) callconv(.Inline) Ctx { if (!enable) return .{}; const loc: ___tracy_source_location_data = .{ diff --git a/src/translate_c.zig b/src/translate_c.zig index 11dbacefa2..b6eaec4286 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -78,6 +78,10 @@ const Scope = struct { mangle_count: u32 = 0, lbrace: ast.TokenIndex, + /// When the block corresponds to a function, keep track of the return type + /// so that the return expression can be cast, if necessary + return_type: ?clang.QualType = null, + fn init(c: *Context, parent: *Scope, labeled: bool) !Block { var blk = Block{ .base = .{ @@ -209,6 +213,21 @@ const Scope = struct { } } + fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType { + var scope = inner; + while (true) { + switch (scope.id) { + .Root => return null, + .Block => { + const block = @fieldParentPtr(Block, "base", scope); + if (block.return_type) |qt| return qt; + scope = scope.parent.?; + }, + else => scope = scope.parent.?, + } + } + } + fn getAlias(scope: *Scope, name: []const u8) []const u8 { return switch (scope.id) { .Root => return name, @@ -580,6 +599,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { else => break fn_type, } } else unreachable; + const fn_ty = @ptrCast(*const clang.FunctionType, fn_type); + const return_qt = fn_ty.getReturnType(); const proto_node = switch (fn_type.getTypeClass()) { .FunctionProto => blk: { @@ -617,7 +638,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { // actual function definition with body const body_stmt = fn_decl.getBody(); var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false); + block_scope.return_type = return_qt; defer block_scope.deinit(); + var scope = &block_scope.base; var param_id: c_uint = 0; @@ -667,10 +690,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { }; // add return statement if the function didn't have one blk: { - const fn_ty = @ptrCast(*const clang.FunctionType, fn_type); - if (fn_ty.getNoReturnAttr()) break :blk; - const return_qt = fn_ty.getReturnType(); if (isCVoid(return_qt)) break :blk; if (block_scope.statements.items.len > 0) { @@ -1418,30 +1438,25 @@ fn transBinaryOperator( switch (op) { .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()), .Comma => { - const block_scope = try scope.findBlockScope(rp.c); - const expr = block_scope.base.parent == scope; - const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined; + var block_scope = try Scope.Block.init(rp.c, scope, true); + const lparen = try appendToken(rp.c, .LParen, "("); const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value); try block_scope.statements.append(lhs); const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value); - if (expr) { - _ = try appendToken(rp.c, .Semicolon, ";"); - const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); - try block_scope.statements.append(&break_node.base); - const block_node = try block_scope.complete(rp.c); - const rparen = try appendToken(rp.c, .RParen, ")"); - const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); - grouped_expr.* = .{ - .lparen = lparen, - .expr = block_node, - .rparen = rparen, - }; - return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); - } else { - return maybeSuppressResult(rp, scope, result_used, rhs); - } + _ = try appendToken(rp.c, .Semicolon, ";"); + const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(rp.c); + const rparen = try appendToken(rp.c, .RParen, ")"); + const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); + grouped_expr.* = .{ + .lparen = lparen, + .expr = block_node, + .rparen = rparen, + }; + return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); }, .Div => { if (cIsSignedInteger(qt)) { @@ -2018,16 +2033,32 @@ fn transIntegerLiteral( return maybeSuppressResult(rp, scope, result_used, &as_node.base); } +/// In C if a function has return type `int` and the return value is a boolean +/// expression, there is no implicit cast. So the translated Zig will need to +/// call @boolToInt +fn zigShouldCastBooleanReturnToInt(node: ?*ast.Node, qt: ?clang.QualType) bool { + if (node == null or qt == null) return false; + return isBoolRes(node.?) and cIsNativeInt(qt.?); +} + fn transReturnStmt( rp: RestorePoint, scope: *Scope, expr: *const clang.ReturnStmt, ) TransError!*ast.Node { const return_kw = try appendToken(rp.c, .Keyword_return, "return"); - const rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr| + var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr| try transExprCoercing(rp, scope, val_expr, .used, .r_value) else null; + const return_qt = scope.findBlockReturnType(rp.c); + if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) { + const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1); + bool_to_int_node.params()[0] = rhs.?; + bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + + rhs = &bool_to_int_node.base; + } const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{ .ltoken = return_kw, .tag = .Return, @@ -3208,6 +3239,38 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySub return maybeSuppressResult(rp, scope, result_used, &node.base); } +/// Check if an expression is ultimately a reference to a function declaration +/// (which means it should not be unwrapped with `.?` in translated code) +fn cIsFunctionDeclRef(expr: *const clang.Expr) bool { + switch (expr.getStmtClass()) { + .ParenExprClass => { + const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr(); + return cIsFunctionDeclRef(op_expr); + }, + .DeclRefExprClass => { + const decl_ref = @ptrCast(*const clang.DeclRefExpr, expr); + const value_decl = decl_ref.getDecl(); + const qt = value_decl.getType(); + return qualTypeChildIsFnProto(qt); + }, + .ImplicitCastExprClass => { + const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, expr); + const cast_kind = implicit_cast.getCastKind(); + if (cast_kind == .BuiltinFnToFnPtr) return true; + if (cast_kind == .FunctionToPointerDecay) { + return cIsFunctionDeclRef(implicit_cast.getSubExpr()); + } + return false; + }, + .UnaryOperatorClass => { + const un_op = @ptrCast(*const clang.UnaryOperator, expr); + const opcode = un_op.getOpcode(); + return (opcode == .AddrOf or opcode == .Deref) and cIsFunctionDeclRef(un_op.getSubExpr()); + }, + else => return false, + } +} + fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!*ast.Node { const callee = stmt.getCallee(); var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value); @@ -3215,24 +3278,9 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r var is_ptr = false; const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr); - const fn_expr = if (is_ptr and fn_ty != null) blk: { - if (callee.getStmtClass() == .ImplicitCastExprClass) { - const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, callee); - const cast_kind = implicit_cast.getCastKind(); - if (cast_kind == .BuiltinFnToFnPtr) break :blk raw_fn_expr; - if (cast_kind == .FunctionToPointerDecay) { - const subexpr = implicit_cast.getSubExpr(); - if (subexpr.getStmtClass() == .DeclRefExprClass) { - const decl_ref = @ptrCast(*const clang.DeclRefExpr, subexpr); - const named_decl = decl_ref.getFoundDecl(); - if (@ptrCast(*const clang.Decl, named_decl).getKind() == .Function) { - break :blk raw_fn_expr; - } - } - } - } - break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); - } else + const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee)) + try transCreateNodeUnwrapNull(rp.c, raw_fn_expr) + else raw_fn_expr; const num_args = stmt.getNumArgs(); @@ -3379,6 +3427,9 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryO else return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), .AddrOf => { + if (cIsFunctionDeclRef(op_expr)) { + return transExpr(rp, scope, op_expr, used, .r_value); + } const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); return &op_node.base; @@ -4665,7 +4716,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a const scope = &c.global_scope.base; const pub_tok = try appendToken(c, .Keyword_pub, "pub"); - const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); const name_tok = try appendIdentifier(c, name); _ = try appendToken(c, .LParen, "("); @@ -4693,6 +4743,11 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a _ = try appendToken(c, .RParen, ")"); + _ = try appendToken(c, .Keyword_callconv, "callconv"); + _ = try appendToken(c, .LParen, "("); + const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline"); + _ = try appendToken(c, .RParen, ")"); + const block_lbrace = try appendToken(c, .LBrace, "{"); const return_kw = try appendToken(c, .Keyword_return, "return"); @@ -4732,8 +4787,8 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a }, .{ .visib_token = pub_tok, .name_token = name_tok, - .extern_export_inline_token = inline_tok, .body_node = &block.base, + .callconv_expr = callconv_expr, }); mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); return &fn_proto.base; @@ -5683,7 +5738,6 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { const scope = &block_scope.base; const pub_tok = try appendToken(c, .Keyword_pub, "pub"); - const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); const name_tok = try appendIdentifier(c, m.name); _ = try appendToken(c, .LParen, "("); @@ -5728,6 +5782,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { _ = try appendToken(c, .RParen, ")"); + _ = try appendToken(c, .Keyword_callconv, "callconv"); + _ = try appendToken(c, .LParen, "("); + const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline"); + _ = try appendToken(c, .RParen, ")"); + const type_of = try c.createBuiltinCall("@TypeOf", 1); const return_kw = try appendToken(c, .Keyword_return, "return"); @@ -5759,9 +5818,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { .return_type = .{ .Explicit = &type_of.base }, }, .{ .visib_token = pub_tok, - .extern_export_inline_token = inline_tok, .name_token = name_tok, .body_node = block_node, + .callconv_expr = callconv_expr, }); mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); diff --git a/src/type.zig b/src/type.zig index 837e1ad29a..e1006e554c 100644 --- a/src/type.zig +++ b/src/type.zig @@ -552,7 +552,9 @@ pub const Type = extern union { if (i != 0) try out_stream.writeAll(", "); try param_type.format("", .{}, out_stream); } - try out_stream.writeAll(") "); + try out_stream.writeAll(") callconv(."); + try out_stream.writeAll(@tagName(payload.cc)); + try out_stream.writeAll(")"); ty = payload.return_type; continue; }, diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 9bd68859e8..8dc6a0823b 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2773,6 +2773,11 @@ struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct Zig return bitcast(casted->getBeginLoc()); } +struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *self) { + auto casted = reinterpret_cast<const clang::ValueDecl *>(self); + return bitcast(casted->getType()); +} + const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { auto casted = reinterpret_cast<const clang::WhileStmt *>(self); return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond()); diff --git a/src/zig_clang.h b/src/zig_clang.h index 42587b1719..6fe1da0bc1 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1200,6 +1200,8 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryOperator_getType(const struct ZIG_EXTERN_C const struct ZigClangExpr *ZigClangUnaryOperator_getSubExpr(const struct ZigClangUnaryOperator *); ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(const struct ZigClangUnaryOperator *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *); + ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *); diff --git a/src/zir.zig b/src/zir.zig index 30bfeead9b..eefded0c6f 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -863,9 +863,7 @@ pub const Inst = struct { fn_type: *Inst, body: Body, }, - kw_args: struct { - is_inline: bool = false, - }, + kw_args: struct {}, }; pub const FnType = struct { @@ -875,10 +873,9 @@ pub const Inst = struct { positionals: struct { param_types: []*Inst, return_type: *Inst, + cc: *Inst, }, - kw_args: struct { - cc: std.builtin.CallingConvention = .Unspecified, - }, + kw_args: struct {}, }; pub const IntType = struct { diff --git a/src/zir_sema.zig b/src/zir_sema.zig index f373d7174d..480e0b4c33 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -980,18 +980,8 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { const b = try mod.requireFunctionBlock(scope, inst.base.src); const is_comptime_call = b.is_comptime or inst.kw_args.modifier == .compile_time; - const is_inline_call = is_comptime_call or inst.kw_args.modifier == .always_inline or blk: { - // This logic will get simplified by - // https://github.com/ziglang/zig/issues/6429 - if (try mod.resolveDefinedValue(scope, func)) |func_val| { - const module_fn = switch (func_val.tag()) { - .function => func_val.castTag(.function).?.data, - else => break :blk false, - }; - break :blk module_fn.state == .inline_only; - } - break :blk false; - }; + const is_inline_call = is_comptime_call or inst.kw_args.modifier == .always_inline or + func.ty.fnCallingConvention() == .Inline; if (is_inline_call) { const func_val = try mod.resolveConstValue(scope, func); const module_fn = switch (func_val.tag()) { @@ -1075,7 +1065,7 @@ fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type); const new_func = try scope.arena().create(Module.Fn); new_func.* = .{ - .state = if (fn_inst.kw_args.is_inline) .inline_only else .queued, + .state = if (fn_type.fnCallingConvention() == .Inline) .inline_only else .queued, .zir = fn_inst.positionals.body, .body = undefined, .owner_decl = scope.ownerDecl().?, @@ -1305,22 +1295,26 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!* const tracy = trace(@src()); defer tracy.end(); const return_type = try resolveType(mod, scope, fntype.positionals.return_type); + const cc_tv = try resolveInstConst(mod, scope, fntype.positionals.cc); + const cc_str = cc_tv.val.castTag(.enum_literal).?.data; + const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse + return mod.fail(scope, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str}); // Hot path for some common function types. if (fntype.positionals.param_types.len == 0) { - if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Unspecified) { + if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { return mod.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args)); } - if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .Unspecified) { + if (return_type.zigTypeTag() == .Void and cc == .Unspecified) { return mod.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args)); } - if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Naked) { + if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) { return mod.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); } - if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .C) { + if (return_type.zigTypeTag() == .Void and cc == .C) { return mod.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); } } @@ -1337,9 +1331,9 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!* } const fn_ty = try Type.Tag.function.create(arena, .{ - .cc = fntype.kw_args.cc, - .return_type = return_type, .param_types = param_types, + .return_type = return_type, + .cc = cc, }); return mod.constType(scope, fntype.base.src, fn_ty); } @@ -1832,7 +1826,7 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; if (!is_int) { - return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) }); + return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) }); } if (casted_lhs.value()) |lhs_val| { |
