diff --git a/BRANCH_TODO b/BRANCH_TODO index 2175d2949b..ce65395c9b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,3 +1,4 @@ + * decouple AstGen from Module, Compilation * modify dbg_stmt ZIR instructions to have line/column rather than node indexes * AstGen threadlocal * extern "foo" for vars and for functions diff --git a/src/AstGen.zig b/src/AstGen.zig index c0ee500d1a..c7706a1dd0 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1048,10 +1048,12 @@ pub fn fnProtoExpr( assert(param_type_i == param_count); } - if (fn_proto.ast.align_expr != 0) { - return astgen.failNode(fn_proto.ast.align_expr, "TODO: AstGen: implement function prototypes with alignment expressions", .{}); + const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { + break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); + }; + if (fn_proto.ast.section_expr != 0) { + return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); } - assert(fn_proto.ast.section_expr == 0); // caught by the parser const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; const is_inferred_error = token_tags[maybe_bang] == .bang; @@ -1081,6 +1083,7 @@ pub fn fnProtoExpr( .param_types = param_types, .body = &[0]Zir.Inst.Index{}, .cc = cc, + .align_inst = align_inst, .lib_name = 0, .is_var_args = is_var_args, .is_inferred_error = false, @@ -2794,6 +2797,7 @@ fn fnDecl( .param_types = param_types, .body = &[0]Zir.Inst.Index{}, .cc = cc, + .align_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = false, @@ -2866,6 +2870,7 @@ fn fnDecl( .param_types = param_types, .body = fn_gz.instructions.items, .cc = cc, + .align_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = is_inferred_error, @@ -3167,6 +3172,7 @@ fn testDecl( .param_types = &[0]Zir.Inst.Ref{}, .body = fn_block.instructions.items, .cc = .none, + .align_inst = .none, .lib_name = 0, .is_var_args = false, .is_inferred_error = true, diff --git a/src/Module.zig b/src/Module.zig index 4b50c298e3..2bbc5383c8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1372,6 +1372,7 @@ pub const Scope = struct { body: []const Zir.Inst.Index, ret_ty: Zir.Inst.Ref, cc: Zir.Inst.Ref, + align_inst: Zir.Inst.Ref, lib_name: u32, is_var_args: bool, is_inferred_error: bool, @@ -1385,12 +1386,15 @@ pub const Scope = struct { try gz.instructions.ensureUnusedCapacity(gpa, 1); try astgen.instructions.ensureUnusedCapacity(gpa, 1); - if (args.cc != .none or args.lib_name != 0 or args.is_var_args or args.is_test) { + if (args.cc != .none or args.lib_name != 0 or + args.is_var_args or args.is_test or args.align_inst != .none) + { try astgen.extra.ensureUnusedCapacity( gpa, @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + args.param_types.len + args.body.len + @boolToInt(args.lib_name != 0) + + @boolToInt(args.align_inst != .none) + @boolToInt(args.cc != .none), ); const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ @@ -1399,11 +1403,14 @@ pub const Scope = struct { .param_types_len = @intCast(u32, args.param_types.len), .body_len = @intCast(u32, args.body.len), }); + if (args.lib_name != 0) { + astgen.extra.appendAssumeCapacity(args.lib_name); + } if (args.cc != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.cc)); } - if (args.lib_name != 0) { - astgen.extra.appendAssumeCapacity(args.lib_name); + if (args.align_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); } astgen.appendRefsAssumeCapacity(args.param_types); astgen.extra.appendSliceAssumeCapacity(args.body); @@ -1418,6 +1425,7 @@ pub const Scope = struct { .is_inferred_error = args.is_inferred_error, .has_lib_name = args.lib_name != 0, .has_cc = args.cc != .none, + .has_align = args.align_inst != .none, .is_test = args.is_test, }), .operand = payload_index, diff --git a/src/Sema.zig b/src/Sema.zig index b532125f12..ba7b87e251 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2737,6 +2737,7 @@ fn zirFunc( body, extra.data.return_type, .Unspecified, + Value.initTag(.null_value), false, inferred_error_set, ); @@ -2750,6 +2751,7 @@ fn funcCommon( body: []const Zir.Inst.Index, zir_return_type: Zir.Inst.Ref, cc: std.builtin.CallingConvention, + align_val: Value, var_args: bool, inferred_error_set: bool, ) InnerError!*Inst { @@ -2762,7 +2764,7 @@ fn funcCommon( } // Hot path for some common function types. - if (zir_param_types.len == 0 and !var_args) { + if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) { if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { return sema.mod.constType(sema.arena, src, Type.initTag(.fn_noreturn_no_args)); } @@ -2789,6 +2791,10 @@ fn funcCommon( param_types[i] = try sema.resolveType(block, src, param_type); } + if (align_val.tag() != .null_value) { + return sema.mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{}); + } + const fn_ty = try Type.Tag.function.create(sema.arena, .{ .param_types = param_types, .return_type = return_type, @@ -5432,6 +5438,7 @@ fn zirFuncExtended( const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand); const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node }; + const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); var extra_index: usize = extra.end; @@ -5455,6 +5462,13 @@ fn zirFuncExtended( break :blk cc; } else .Unspecified; + const align_val: Value = if (small.has_align) blk: { + const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); + extra_index += 1; + const align_tv = try sema.resolveInstConst(block, align_src, align_ref); + break :blk align_tv.val; + } else Value.initTag(.null_value); + const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len); extra_index += param_types.len; @@ -5467,6 +5481,7 @@ fn zirFuncExtended( body, extra.data.return_type, cc, + align_val, small.is_var_args, small.is_inferred_error, ); diff --git a/src/Zir.zig b/src/Zir.zig index 9692415407..065649c118 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2189,8 +2189,9 @@ pub const Inst = struct { /// Trailing: /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set /// 1. cc: Ref, // if has_cc is set - /// 2. param_type: Ref // for each param_types_len - /// 3. body: Index // for each body_len + /// 2. align: Ref, // if has_align is set + /// 3. param_type: Ref // for each param_types_len + /// 4. body: Index // for each body_len pub const ExtendedFunc = struct { src_node: i32, return_type: Ref, @@ -2202,8 +2203,9 @@ pub const Inst = struct { is_inferred_error: bool, has_lib_name: bool, has_cc: bool, + has_align: bool, is_test: bool, - _: u11 = undefined, + _: u10 = undefined, }; }; @@ -3966,6 +3968,7 @@ const Writer = struct { inferred_error_set, false, .none, + .none, body, src, ); @@ -3988,6 +3991,11 @@ const Writer = struct { extra_index += 1; break :blk cc; }; + const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { + const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk align_inst; + }; const param_types = self.code.refSlice(extra_index, extra.data.param_types_len); extra_index += param_types.len; @@ -4001,6 +4009,7 @@ const Writer = struct { small.is_inferred_error, small.is_var_args, cc, + align_inst, body, src, ); @@ -4053,6 +4062,7 @@ const Writer = struct { inferred_error_set: bool, var_args: bool, cc: Inst.Ref, + align_inst: Inst.Ref, body: []const Inst.Index, src: LazySrcLoc, ) !void { @@ -4064,6 +4074,7 @@ const Writer = struct { try stream.writeAll("], "); try self.writeInstRef(stream, ret_ty); try self.writeOptionalInstRef(stream, ", cc=", cc); + try self.writeOptionalInstRef(stream, ", align=", align_inst); try self.writeFlag(stream, ", vargs", var_args); try self.writeFlag(stream, ", inferror", inferred_error_set);