aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Cache.zig2
-rw-r--r--src/Compilation.zig6
-rw-r--r--src/Module.zig37
-rw-r--r--src/clang.zig5
-rw-r--r--src/clang_options_data.zig9
-rw-r--r--src/codegen.zig106
-rw-r--r--src/codegen/arm.zig2
-rw-r--r--src/link/MachO.zig2
-rw-r--r--src/main.zig7
-rw-r--r--src/musl.zig14
-rw-r--r--src/stage1.zig4
-rw-r--r--src/stage1/all_types.hpp12
-rw-r--r--src/stage1/analyze.cpp20
-rw-r--r--src/stage1/ast_render.cpp11
-rw-r--r--src/stage1/codegen.cpp46
-rw-r--r--src/stage1/ir.cpp23
-rw-r--r--src/stage1/parser.cpp17
-rw-r--r--src/tracy.zig2
-rw-r--r--src/translate_c.zig149
-rw-r--r--src/type.zig4
-rw-r--r--src/zig_clang.cpp5
-rw-r--r--src/zig_clang.h2
-rw-r--r--src/zir.zig9
-rw-r--r--src/zir_sema.zig34
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| {