mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 15:19:07 +00:00
commit
7c527c6dfe
20 changed files with 454 additions and 89 deletions
|
|
@ -1044,7 +1044,8 @@ pub const Struct = struct {
|
||||||
|
|
||||||
.root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()),
|
.root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()),
|
||||||
|
|
||||||
else => unreachable,
|
// This struct was generated using @Type
|
||||||
|
else => return s.srcLoc(mod),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1270,7 +1271,8 @@ pub const Union = struct {
|
||||||
.tagged_union_enum_tag,
|
.tagged_union_enum_tag,
|
||||||
.tagged_union_enum_tag_trailing,
|
.tagged_union_enum_tag_trailing,
|
||||||
=> return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
|
=> return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
|
||||||
else => unreachable,
|
// This union was generated using @Type
|
||||||
|
else => return u.srcLoc(mod),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4631,7 +4633,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||||
const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
|
const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
|
||||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
|
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
|
||||||
const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
|
const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
|
||||||
const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, undefined);
|
const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, "global variable initializer must be comptime-known");
|
||||||
|
|
||||||
// Note this resolves the type of the Decl, not the value; if this Decl
|
// Note this resolves the type of the Decl, not the value; if this Decl
|
||||||
// is a struct, for example, this resolves `type` (which needs no resolution),
|
// is a struct, for example, this resolves `type` (which needs no resolution),
|
||||||
|
|
|
||||||
98
src/Sema.zig
98
src/Sema.zig
|
|
@ -128,7 +128,7 @@ pub const Block = struct {
|
||||||
/// Shared among all child blocks.
|
/// Shared among all child blocks.
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
/// The namespace to use for lookups from this source block
|
/// The namespace to use for lookups from this source block
|
||||||
/// When analyzing fields, this is different from src_decl.src_namepsace.
|
/// When analyzing fields, this is different from src_decl.src_namespace.
|
||||||
namespace: *Namespace,
|
namespace: *Namespace,
|
||||||
/// The AIR instructions generated for this block.
|
/// The AIR instructions generated for this block.
|
||||||
instructions: std.ArrayListUnmanaged(Air.Inst.Index),
|
instructions: std.ArrayListUnmanaged(Air.Inst.Index),
|
||||||
|
|
@ -1897,10 +1897,15 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
|
||||||
}
|
}
|
||||||
i -= Air.Inst.Ref.typed_value_map.len;
|
i -= Air.Inst.Ref.typed_value_map.len;
|
||||||
|
|
||||||
|
const air_tags = sema.air_instructions.items(.tag);
|
||||||
if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
|
if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
|
||||||
|
if (air_tags[i] == .constant) {
|
||||||
|
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
|
||||||
|
const val = sema.air_values.items[ty_pl.payload];
|
||||||
|
if (val.tag() == .variable) return val;
|
||||||
|
}
|
||||||
return opv;
|
return opv;
|
||||||
}
|
}
|
||||||
const air_tags = sema.air_instructions.items(.tag);
|
|
||||||
switch (air_tags[i]) {
|
switch (air_tags[i]) {
|
||||||
.constant => {
|
.constant => {
|
||||||
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
|
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
|
||||||
|
|
@ -4106,6 +4111,7 @@ fn validateStructInit(
|
||||||
.{fqn},
|
.{fqn},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4225,7 +4231,6 @@ fn validateStructInit(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
root_msg = null;
|
|
||||||
if (struct_ty.castTag(.@"struct")) |struct_obj| {
|
if (struct_ty.castTag(.@"struct")) |struct_obj| {
|
||||||
const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
|
const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
|
||||||
defer gpa.free(fqn);
|
defer gpa.free(fqn);
|
||||||
|
|
@ -4236,6 +4241,7 @@ fn validateStructInit(
|
||||||
.{fqn},
|
.{fqn},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4283,29 +4289,42 @@ fn zirValidateArrayInit(
|
||||||
const array_ty = sema.typeOf(array_ptr).childType();
|
const array_ty = sema.typeOf(array_ptr).childType();
|
||||||
const array_len = array_ty.arrayLen();
|
const array_len = array_ty.arrayLen();
|
||||||
|
|
||||||
if (instrs.len != array_len and array_ty.isTuple()) {
|
if (instrs.len != array_len) switch (array_ty.zigTypeTag()) {
|
||||||
const struct_obj = array_ty.castTag(.tuple).?.data;
|
.Struct => {
|
||||||
var root_msg: ?*Module.ErrorMsg = null;
|
const struct_obj = array_ty.castTag(.tuple).?.data;
|
||||||
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
|
var root_msg: ?*Module.ErrorMsg = null;
|
||||||
|
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
|
||||||
|
|
||||||
for (struct_obj.values) |default_val, i| {
|
for (struct_obj.values) |default_val, i| {
|
||||||
if (i < instrs.len) continue;
|
if (i < instrs.len) continue;
|
||||||
|
|
||||||
if (default_val.tag() == .unreachable_value) {
|
if (default_val.tag() == .unreachable_value) {
|
||||||
const template = "missing tuple field with index {d}";
|
const template = "missing tuple field with index {d}";
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
try sema.errNote(block, init_src, msg, template, .{i});
|
try sema.errNote(block, init_src, msg, template, .{i});
|
||||||
} else {
|
} else {
|
||||||
root_msg = try sema.errMsg(block, init_src, template, .{i});
|
root_msg = try sema.errMsg(block, init_src, template, .{i});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
root_msg = null;
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
.Array => {
|
||||||
|
return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
|
||||||
|
array_len, instrs.len,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.Vector => {
|
||||||
|
return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
|
||||||
|
array_len, instrs.len,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
if ((is_comptime or block.is_comptime) and
|
if ((is_comptime or block.is_comptime) and
|
||||||
(try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
|
(try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
|
||||||
|
|
@ -17080,7 +17099,6 @@ fn finishStructInit(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
root_msg = null;
|
|
||||||
if (struct_ty.castTag(.@"struct")) |struct_obj| {
|
if (struct_ty.castTag(.@"struct")) |struct_obj| {
|
||||||
const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
|
const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
|
||||||
defer gpa.free(fqn);
|
defer gpa.free(fqn);
|
||||||
|
|
@ -17091,6 +17109,7 @@ fn finishStructInit(
|
||||||
.{fqn},
|
.{fqn},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18778,8 +18797,8 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||||
|
|
||||||
const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||||
const ptr_ty = try sema.resolveType(block, src, extra.lhs);
|
const ptr_ty = try sema.resolveType(block, src, extra.lhs);
|
||||||
const elem_ty = ptr_ty.elemType2();
|
|
||||||
try sema.checkPtrType(block, type_src, ptr_ty);
|
try sema.checkPtrType(block, type_src, ptr_ty);
|
||||||
|
const elem_ty = ptr_ty.elemType2();
|
||||||
const target = sema.mod.getTarget();
|
const target = sema.mod.getTarget();
|
||||||
const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema);
|
const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema);
|
||||||
|
|
||||||
|
|
@ -24307,7 +24326,10 @@ fn coerceExtra(
|
||||||
},
|
},
|
||||||
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
|
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
|
||||||
.Float, .ComptimeFloat => float: {
|
.Float, .ComptimeFloat => float: {
|
||||||
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse {
|
if (is_undef) {
|
||||||
|
return sema.addConstUndef(dest_ty);
|
||||||
|
}
|
||||||
|
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
||||||
if (dest_ty.zigTypeTag() == .ComptimeInt) {
|
if (dest_ty.zigTypeTag() == .ComptimeInt) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
|
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
|
||||||
|
|
@ -24327,7 +24349,10 @@ fn coerceExtra(
|
||||||
return try sema.addConstant(dest_ty, result_val);
|
return try sema.addConstant(dest_ty, result_val);
|
||||||
},
|
},
|
||||||
.Int, .ComptimeInt => {
|
.Int, .ComptimeInt => {
|
||||||
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
if (is_undef) {
|
||||||
|
return sema.addConstUndef(dest_ty);
|
||||||
|
}
|
||||||
|
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
||||||
// comptime-known integer to other number
|
// comptime-known integer to other number
|
||||||
if (!(try sema.intFitsInType(val, dest_ty, null))) {
|
if (!(try sema.intFitsInType(val, dest_ty, null))) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
|
|
@ -24364,7 +24389,10 @@ fn coerceExtra(
|
||||||
return try sema.addConstant(dest_ty, result_val);
|
return try sema.addConstant(dest_ty, result_val);
|
||||||
},
|
},
|
||||||
.Float => {
|
.Float => {
|
||||||
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
if (is_undef) {
|
||||||
|
return sema.addConstUndef(dest_ty);
|
||||||
|
}
|
||||||
|
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
||||||
const result_val = try val.floatCast(sema.arena, dest_ty, target);
|
const result_val = try val.floatCast(sema.arena, dest_ty, target);
|
||||||
if (!val.eql(result_val, dest_ty, sema.mod)) {
|
if (!val.eql(result_val, dest_ty, sema.mod)) {
|
||||||
return sema.fail(
|
return sema.fail(
|
||||||
|
|
@ -24389,7 +24417,10 @@ fn coerceExtra(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Int, .ComptimeInt => int: {
|
.Int, .ComptimeInt => int: {
|
||||||
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse {
|
if (is_undef) {
|
||||||
|
return sema.addConstUndef(dest_ty);
|
||||||
|
}
|
||||||
|
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
||||||
if (dest_ty.zigTypeTag() == .ComptimeFloat) {
|
if (dest_ty.zigTypeTag() == .ComptimeFloat) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
|
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
|
||||||
|
|
@ -26543,6 +26574,10 @@ fn beginComptimePtrLoad(
|
||||||
.null_value => {
|
.null_value => {
|
||||||
return sema.fail(block, src, "attempt to use null value", .{});
|
return sema.fail(block, src, "attempt to use null value", .{});
|
||||||
},
|
},
|
||||||
|
.opt_payload => blk: {
|
||||||
|
const opt_payload = ptr_val.castTag(.opt_payload).?.data;
|
||||||
|
break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null);
|
||||||
|
},
|
||||||
|
|
||||||
.zero,
|
.zero,
|
||||||
.one,
|
.one,
|
||||||
|
|
@ -27191,8 +27226,8 @@ fn coerceTupleToStruct(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
root_msg = null;
|
|
||||||
try sema.addDeclaredHereNote(msg, struct_ty);
|
try sema.addDeclaredHereNote(msg, struct_ty);
|
||||||
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27297,8 +27332,8 @@ fn coerceTupleToTuple(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_msg) |msg| {
|
if (root_msg) |msg| {
|
||||||
root_msg = null;
|
|
||||||
try sema.addDeclaredHereNote(msg, tuple_ty);
|
try sema.addDeclaredHereNote(msg, tuple_ty);
|
||||||
|
root_msg = null;
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31298,7 +31333,10 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
|
pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
return ty.hasRuntimeBitsAdvanced(false, sema);
|
return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
|
fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
|
||||||
|
|
|
||||||
|
|
@ -988,6 +988,25 @@ pub const Object = struct {
|
||||||
args.appendAssumeCapacity(load_inst);
|
args.appendAssumeCapacity(load_inst);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.byref_mut => {
|
||||||
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
|
const param_llvm_ty = try dg.lowerType(param_ty);
|
||||||
|
const param = llvm_func.getParam(llvm_arg_i);
|
||||||
|
const alignment = param_ty.abiAlignment(target);
|
||||||
|
|
||||||
|
dg.addArgAttr(llvm_func, llvm_arg_i, "noundef");
|
||||||
|
llvm_arg_i += 1;
|
||||||
|
|
||||||
|
try args.ensureUnusedCapacity(1);
|
||||||
|
|
||||||
|
if (isByRef(param_ty)) {
|
||||||
|
args.appendAssumeCapacity(param);
|
||||||
|
} else {
|
||||||
|
const load_inst = builder.buildLoad(param_llvm_ty, param, "");
|
||||||
|
load_inst.setAlignment(alignment);
|
||||||
|
args.appendAssumeCapacity(load_inst);
|
||||||
|
}
|
||||||
|
},
|
||||||
.abi_sized_int => {
|
.abi_sized_int => {
|
||||||
assert(!it.byval_attr);
|
assert(!it.byval_attr);
|
||||||
const param_ty = fn_info.param_types[it.zig_index - 1];
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
|
|
@ -2583,6 +2602,9 @@ pub const DeclGen = struct {
|
||||||
const alignment = param_ty.abiAlignment(target);
|
const alignment = param_ty.abiAlignment(target);
|
||||||
dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
|
dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
|
||||||
},
|
},
|
||||||
|
.byref_mut => {
|
||||||
|
dg.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
|
||||||
|
},
|
||||||
// No attributes needed for these.
|
// No attributes needed for these.
|
||||||
.no_bits,
|
.no_bits,
|
||||||
.abi_sized_int,
|
.abi_sized_int,
|
||||||
|
|
@ -3101,7 +3123,7 @@ pub const DeclGen = struct {
|
||||||
const param_ty = fn_info.param_types[it.zig_index - 1];
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
try llvm_params.append(try dg.lowerType(param_ty));
|
try llvm_params.append(try dg.lowerType(param_ty));
|
||||||
},
|
},
|
||||||
.byref => {
|
.byref, .byref_mut => {
|
||||||
const param_ty = fn_info.param_types[it.zig_index - 1];
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
const raw_llvm_ty = try dg.lowerType(param_ty);
|
const raw_llvm_ty = try dg.lowerType(param_ty);
|
||||||
try llvm_params.append(raw_llvm_ty.pointerType(0));
|
try llvm_params.append(raw_llvm_ty.pointerType(0));
|
||||||
|
|
@ -4678,9 +4700,9 @@ pub const FuncGen = struct {
|
||||||
break :blk ret_ptr;
|
break :blk ret_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fn_info.return_type.isError() and
|
const err_return_tracing = fn_info.return_type.isError() and
|
||||||
self.dg.module.comp.bin_file.options.error_return_tracing)
|
self.dg.module.comp.bin_file.options.error_return_tracing;
|
||||||
{
|
if (err_return_tracing) {
|
||||||
try llvm_args.append(self.err_ret_trace.?);
|
try llvm_args.append(self.err_ret_trace.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4726,6 +4748,27 @@ pub const FuncGen = struct {
|
||||||
try llvm_args.append(arg_ptr);
|
try llvm_args.append(arg_ptr);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.byref_mut => {
|
||||||
|
const arg = args[it.zig_index - 1];
|
||||||
|
const param_ty = self.air.typeOf(arg);
|
||||||
|
const llvm_arg = try self.resolveInst(arg);
|
||||||
|
|
||||||
|
const alignment = param_ty.abiAlignment(target);
|
||||||
|
const param_llvm_ty = try self.dg.lowerType(param_ty);
|
||||||
|
const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
|
||||||
|
if (isByRef(param_ty)) {
|
||||||
|
const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");
|
||||||
|
load_inst.setAlignment(alignment);
|
||||||
|
|
||||||
|
const store_inst = self.builder.buildStore(load_inst, arg_ptr);
|
||||||
|
store_inst.setAlignment(alignment);
|
||||||
|
try llvm_args.append(arg_ptr);
|
||||||
|
} else {
|
||||||
|
const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
|
||||||
|
store_inst.setAlignment(alignment);
|
||||||
|
try llvm_args.append(arg_ptr);
|
||||||
|
}
|
||||||
|
},
|
||||||
.abi_sized_int => {
|
.abi_sized_int => {
|
||||||
const arg = args[it.zig_index - 1];
|
const arg = args[it.zig_index - 1];
|
||||||
const param_ty = self.air.typeOf(arg);
|
const param_ty = self.air.typeOf(arg);
|
||||||
|
|
@ -4847,6 +4890,66 @@ pub const FuncGen = struct {
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (callee_ty.zigTypeTag() == .Pointer) {
|
||||||
|
// Add argument attributes for function pointer calls.
|
||||||
|
it = iterateParamTypes(self.dg, fn_info);
|
||||||
|
it.llvm_index += @boolToInt(sret);
|
||||||
|
it.llvm_index += @boolToInt(err_return_tracing);
|
||||||
|
while (it.next()) |lowering| switch (lowering) {
|
||||||
|
.byval => {
|
||||||
|
const param_index = it.zig_index - 1;
|
||||||
|
const param_ty = fn_info.param_types[param_index];
|
||||||
|
if (!isByRef(param_ty)) {
|
||||||
|
self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.byref => {
|
||||||
|
const param_index = it.zig_index - 1;
|
||||||
|
const param_ty = fn_info.param_types[param_index];
|
||||||
|
const param_llvm_ty = try self.dg.lowerType(param_ty);
|
||||||
|
const alignment = param_ty.abiAlignment(target);
|
||||||
|
self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
|
||||||
|
},
|
||||||
|
.byref_mut => {
|
||||||
|
self.dg.addArgAttr(call, it.llvm_index - 1, "noundef");
|
||||||
|
},
|
||||||
|
// No attributes needed for these.
|
||||||
|
.no_bits,
|
||||||
|
.abi_sized_int,
|
||||||
|
.multiple_llvm_types,
|
||||||
|
.as_u16,
|
||||||
|
.float_array,
|
||||||
|
.i32_array,
|
||||||
|
.i64_array,
|
||||||
|
=> continue,
|
||||||
|
|
||||||
|
.slice => {
|
||||||
|
assert(!it.byval_attr);
|
||||||
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
|
const ptr_info = param_ty.ptrInfo().data;
|
||||||
|
const llvm_arg_i = it.llvm_index - 2;
|
||||||
|
|
||||||
|
if (math.cast(u5, it.zig_index - 1)) |i| {
|
||||||
|
if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "noalias");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param_ty.zigTypeTag() != .Optional) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "nonnull");
|
||||||
|
}
|
||||||
|
if (!ptr_info.mutable) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "readonly");
|
||||||
|
}
|
||||||
|
if (ptr_info.@"align" != 0) {
|
||||||
|
self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align");
|
||||||
|
} else {
|
||||||
|
const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1);
|
||||||
|
self.dg.addArgAttrInt(call, llvm_arg_i, "align", elem_align);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (return_type.isNoReturn() and attr != .AlwaysTail) {
|
if (return_type.isNoReturn() and attr != .AlwaysTail) {
|
||||||
_ = self.builder.buildUnreachable();
|
_ = self.builder.buildUnreachable();
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -4876,7 +4979,7 @@ pub const FuncGen = struct {
|
||||||
// In this case the function return type is honoring the calling convention by having
|
// In this case the function return type is honoring the calling convention by having
|
||||||
// a different LLVM type than the usual one. We solve this here at the callsite
|
// a different LLVM type than the usual one. We solve this here at the callsite
|
||||||
// by bitcasting a pointer to our canonical type, then loading it if necessary.
|
// by bitcasting a pointer to our canonical type, then loading it if necessary.
|
||||||
const alignment = return_type.abiAlignment(target);
|
const alignment = self.dg.object.target_data.abiAlignmentOfType(abi_ret_ty);
|
||||||
const rp = self.buildAlloca(llvm_ret_ty, alignment);
|
const rp = self.buildAlloca(llvm_ret_ty, alignment);
|
||||||
const ptr_abi_ty = abi_ret_ty.pointerType(0);
|
const ptr_abi_ty = abi_ret_ty.pointerType(0);
|
||||||
const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
|
const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
|
||||||
|
|
@ -10384,6 +10487,7 @@ const ParamTypeIterator = struct {
|
||||||
no_bits,
|
no_bits,
|
||||||
byval,
|
byval,
|
||||||
byref,
|
byref,
|
||||||
|
byref_mut,
|
||||||
abi_sized_int,
|
abi_sized_int,
|
||||||
multiple_llvm_types,
|
multiple_llvm_types,
|
||||||
slice,
|
slice,
|
||||||
|
|
@ -10425,6 +10529,7 @@ const ParamTypeIterator = struct {
|
||||||
it.llvm_index += 1;
|
it.llvm_index += 1;
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.Payload.ElemType = undefined;
|
||||||
if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
|
if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
|
||||||
|
it.llvm_index += 1;
|
||||||
return .slice;
|
return .slice;
|
||||||
} else if (isByRef(ty)) {
|
} else if (isByRef(ty)) {
|
||||||
return .byref;
|
return .byref;
|
||||||
|
|
@ -10547,7 +10652,7 @@ const ParamTypeIterator = struct {
|
||||||
it.zig_index += 1;
|
it.zig_index += 1;
|
||||||
it.llvm_index += 1;
|
it.llvm_index += 1;
|
||||||
switch (aarch64_c_abi.classifyType(ty, it.target)) {
|
switch (aarch64_c_abi.classifyType(ty, it.target)) {
|
||||||
.memory => return .byref,
|
.memory => return .byref_mut,
|
||||||
.float_array => |len| return Lowering{ .float_array = len },
|
.float_array => |len| return Lowering{ .float_array = len },
|
||||||
.byval => return .byval,
|
.byval => return .byval,
|
||||||
.integer => {
|
.integer => {
|
||||||
|
|
@ -10578,9 +10683,7 @@ const ParamTypeIterator = struct {
|
||||||
return .as_u16;
|
return .as_u16;
|
||||||
}
|
}
|
||||||
switch (riscv_c_abi.classifyType(ty, it.target)) {
|
switch (riscv_c_abi.classifyType(ty, it.target)) {
|
||||||
.memory => {
|
.memory => return .byref_mut,
|
||||||
return .byref;
|
|
||||||
},
|
|
||||||
.byval => return .byval,
|
.byval => return .byval,
|
||||||
.integer => return .abi_sized_int,
|
.integer => return .abi_sized_int,
|
||||||
.double_integer => return Lowering{ .i64_array = 2 },
|
.double_integer => return Lowering{ .i64_array = 2 },
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ pub const Context = opaque {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = opaque {
|
pub const Value = opaque {
|
||||||
pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
|
pub const addAttributeAtIndex = ZigLLVMAddAttributeAtIndex;
|
||||||
extern fn LLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
extern fn ZigLLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
||||||
|
|
||||||
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
|
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
|
||||||
extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void;
|
extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void;
|
||||||
|
|
|
||||||
|
|
@ -1304,7 +1304,11 @@ fn buildOutputType(
|
||||||
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
|
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
|
||||||
linker_gc_sections = false;
|
linker_gc_sections = false;
|
||||||
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
|
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
|
||||||
debug_compile_errors = true;
|
if (!crash_report.is_enabled) {
|
||||||
|
std.log.warn("Zig was compiled in a release mode. --debug-compile-errors has no effect.", .{});
|
||||||
|
} else {
|
||||||
|
debug_compile_errors = true;
|
||||||
|
}
|
||||||
} else if (mem.eql(u8, arg, "--verbose-link")) {
|
} else if (mem.eql(u8, arg, "--verbose-link")) {
|
||||||
verbose_link = true;
|
verbose_link = true;
|
||||||
} else if (mem.eql(u8, arg, "--verbose-cc")) {
|
} else if (mem.eql(u8, arg, "--verbose-cc")) {
|
||||||
|
|
|
||||||
|
|
@ -400,9 +400,13 @@ const Writer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
const data = w.air.instructions.items(.data);
|
||||||
|
const ty_pl = data[inst].ty_pl;
|
||||||
const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
|
const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||||
|
|
||||||
|
const inst_ty = w.air.getRefType(data[inst].ty_pl.ty);
|
||||||
|
try w.writeType(s, inst_ty);
|
||||||
|
try s.writeAll(", ");
|
||||||
try w.writeOperand(s, inst, 0, extra.lhs);
|
try w.writeOperand(s, inst, 0, extra.lhs);
|
||||||
try s.writeAll(", ");
|
try s.writeAll(", ");
|
||||||
try w.writeOperand(s, inst, 1, extra.rhs);
|
try w.writeOperand(s, inst, 1, extra.rhs);
|
||||||
|
|
|
||||||
|
|
@ -262,9 +262,10 @@ const Writer = struct {
|
||||||
=> try self.writeBreak(stream, inst),
|
=> try self.writeBreak(stream, inst),
|
||||||
.array_init,
|
.array_init,
|
||||||
.array_init_ref,
|
.array_init_ref,
|
||||||
|
=> try self.writeArrayInit(stream, inst),
|
||||||
.array_init_anon,
|
.array_init_anon,
|
||||||
.array_init_anon_ref,
|
.array_init_anon_ref,
|
||||||
=> try self.writeArrayInit(stream, inst),
|
=> try self.writeArrayInitAnon(stream, inst),
|
||||||
|
|
||||||
.slice_start => try self.writeSliceStart(stream, inst),
|
.slice_start => try self.writeSliceStart(stream, inst),
|
||||||
.slice_end => try self.writeSliceEnd(stream, inst),
|
.slice_end => try self.writeSliceEnd(stream, inst),
|
||||||
|
|
@ -2316,6 +2317,21 @@ const Writer = struct {
|
||||||
try self.writeSrc(stream, inst_data.src());
|
try self.writeSrc(stream, inst_data.src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn writeArrayInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||||
|
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||||
|
|
||||||
|
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
|
||||||
|
const args = self.code.refSlice(extra.end, extra.data.operands_len);
|
||||||
|
|
||||||
|
try stream.writeAll("{");
|
||||||
|
for (args) |arg, i| {
|
||||||
|
if (i != 0) try stream.writeAll(", ");
|
||||||
|
try self.writeInstRef(stream, arg);
|
||||||
|
}
|
||||||
|
try stream.writeAll("}) ");
|
||||||
|
try self.writeSrc(stream, inst_data.src());
|
||||||
|
}
|
||||||
|
|
||||||
fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||||
|
|
||||||
|
|
|
||||||
81
src/type.zig
81
src/type.zig
|
|
@ -2312,6 +2312,8 @@ pub const Type = extern union {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RuntimeBitsError = Module.CompileError || error{NeedLazy};
|
||||||
|
|
||||||
/// true if and only if the type takes up space in memory at runtime.
|
/// true if and only if the type takes up space in memory at runtime.
|
||||||
/// There are two reasons a type will return false:
|
/// There are two reasons a type will return false:
|
||||||
/// * the type is a comptime-only type. For example, the type `type` itself.
|
/// * the type is a comptime-only type. For example, the type `type` itself.
|
||||||
|
|
@ -2326,8 +2328,8 @@ pub const Type = extern union {
|
||||||
pub fn hasRuntimeBitsAdvanced(
|
pub fn hasRuntimeBitsAdvanced(
|
||||||
ty: Type,
|
ty: Type,
|
||||||
ignore_comptime_only: bool,
|
ignore_comptime_only: bool,
|
||||||
opt_sema: ?*Sema,
|
strat: AbiAlignmentAdvancedStrat,
|
||||||
) Module.CompileError!bool {
|
) RuntimeBitsError!bool {
|
||||||
switch (ty.tag()) {
|
switch (ty.tag()) {
|
||||||
.u1,
|
.u1,
|
||||||
.u8,
|
.u8,
|
||||||
|
|
@ -2406,8 +2408,8 @@ pub const Type = extern union {
|
||||||
return true;
|
return true;
|
||||||
} else if (ty.childType().zigTypeTag() == .Fn) {
|
} else if (ty.childType().zigTypeTag() == .Fn) {
|
||||||
return !ty.childType().fnInfo().is_generic;
|
return !ty.childType().fnInfo().is_generic;
|
||||||
} else if (opt_sema) |sema| {
|
} else if (strat == .sema) {
|
||||||
return !(try sema.typeRequiresComptime(ty));
|
return !(try strat.sema.typeRequiresComptime(ty));
|
||||||
} else {
|
} else {
|
||||||
return !comptimeOnly(ty);
|
return !comptimeOnly(ty);
|
||||||
}
|
}
|
||||||
|
|
@ -2445,8 +2447,8 @@ pub const Type = extern union {
|
||||||
}
|
}
|
||||||
if (ignore_comptime_only) {
|
if (ignore_comptime_only) {
|
||||||
return true;
|
return true;
|
||||||
} else if (opt_sema) |sema| {
|
} else if (strat == .sema) {
|
||||||
return !(try sema.typeRequiresComptime(child_ty));
|
return !(try strat.sema.typeRequiresComptime(child_ty));
|
||||||
} else {
|
} else {
|
||||||
return !comptimeOnly(child_ty);
|
return !comptimeOnly(child_ty);
|
||||||
}
|
}
|
||||||
|
|
@ -2459,13 +2461,14 @@ pub const Type = extern union {
|
||||||
// and then later if our guess was incorrect, we emit a compile error.
|
// and then later if our guess was incorrect, we emit a compile error.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (opt_sema) |sema| {
|
switch (strat) {
|
||||||
_ = try sema.resolveTypeFields(ty);
|
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
||||||
|
.eager => assert(struct_obj.haveFieldTypes()),
|
||||||
|
.lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy,
|
||||||
}
|
}
|
||||||
assert(struct_obj.haveFieldTypes());
|
|
||||||
for (struct_obj.fields.values()) |field| {
|
for (struct_obj.fields.values()) |field| {
|
||||||
if (field.is_comptime) continue;
|
if (field.is_comptime) continue;
|
||||||
if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
|
if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2474,7 +2477,7 @@ pub const Type = extern union {
|
||||||
|
|
||||||
.enum_full => {
|
.enum_full => {
|
||||||
const enum_full = ty.castTag(.enum_full).?.data;
|
const enum_full = ty.castTag(.enum_full).?.data;
|
||||||
return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);
|
return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
|
||||||
},
|
},
|
||||||
.enum_simple => {
|
.enum_simple => {
|
||||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||||
|
|
@ -2483,17 +2486,18 @@ pub const Type = extern union {
|
||||||
.enum_numbered, .enum_nonexhaustive => {
|
.enum_numbered, .enum_nonexhaustive => {
|
||||||
var buffer: Payload.Bits = undefined;
|
var buffer: Payload.Bits = undefined;
|
||||||
const int_tag_ty = ty.intTagType(&buffer);
|
const int_tag_ty = ty.intTagType(&buffer);
|
||||||
return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);
|
return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union" => {
|
.@"union" => {
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
const union_obj = ty.castTag(.@"union").?.data;
|
||||||
if (opt_sema) |sema| {
|
switch (strat) {
|
||||||
_ = try sema.resolveTypeFields(ty);
|
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
||||||
|
.eager => assert(union_obj.haveFieldTypes()),
|
||||||
|
.lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
|
||||||
}
|
}
|
||||||
assert(union_obj.haveFieldTypes());
|
|
||||||
for (union_obj.fields.values()) |value| {
|
for (union_obj.fields.values()) |value| {
|
||||||
if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
|
if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2501,16 +2505,17 @@ pub const Type = extern union {
|
||||||
},
|
},
|
||||||
.union_safety_tagged, .union_tagged => {
|
.union_safety_tagged, .union_tagged => {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
const union_obj = ty.cast(Payload.Union).?.data;
|
||||||
if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) {
|
if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_sema) |sema| {
|
switch (strat) {
|
||||||
_ = try sema.resolveTypeFields(ty);
|
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
||||||
|
.eager => assert(union_obj.haveFieldTypes()),
|
||||||
|
.lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
|
||||||
}
|
}
|
||||||
assert(union_obj.haveFieldTypes());
|
|
||||||
for (union_obj.fields.values()) |value| {
|
for (union_obj.fields.values()) |value| {
|
||||||
if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
|
if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2518,9 +2523,9 @@ pub const Type = extern union {
|
||||||
},
|
},
|
||||||
|
|
||||||
.array, .vector => return ty.arrayLen() != 0 and
|
.array, .vector => return ty.arrayLen() != 0 and
|
||||||
try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),
|
try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
|
||||||
.array_u8 => return ty.arrayLen() != 0,
|
.array_u8 => return ty.arrayLen() != 0,
|
||||||
.array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),
|
.array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
|
||||||
|
|
||||||
.int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
|
.int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
|
||||||
|
|
||||||
|
|
@ -2529,7 +2534,7 @@ pub const Type = extern union {
|
||||||
for (tuple.types) |field_ty, i| {
|
for (tuple.types) |field_ty, i| {
|
||||||
const val = tuple.values[i];
|
const val = tuple.values[i];
|
||||||
if (val.tag() != .unreachable_value) continue; // comptime field
|
if (val.tag() != .unreachable_value) continue; // comptime field
|
||||||
if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) return true;
|
if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
@ -2665,11 +2670,11 @@ pub const Type = extern union {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasRuntimeBits(ty: Type) bool {
|
pub fn hasRuntimeBits(ty: Type) bool {
|
||||||
return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable;
|
return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
|
pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
|
||||||
return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable;
|
return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isFnOrHasRuntimeBits(ty: Type) bool {
|
pub fn isFnOrHasRuntimeBits(ty: Type) bool {
|
||||||
|
|
@ -2812,12 +2817,12 @@ pub const Type = extern union {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbiAlignmentAdvanced = union(enum) {
|
pub const AbiAlignmentAdvanced = union(enum) {
|
||||||
scalar: u32,
|
scalar: u32,
|
||||||
val: Value,
|
val: Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
const AbiAlignmentAdvancedStrat = union(enum) {
|
pub const AbiAlignmentAdvancedStrat = union(enum) {
|
||||||
eager,
|
eager,
|
||||||
lazy: Allocator,
|
lazy: Allocator,
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
|
|
@ -2971,7 +2976,10 @@ pub const Type = extern union {
|
||||||
|
|
||||||
switch (strat) {
|
switch (strat) {
|
||||||
.eager, .sema => {
|
.eager, .sema => {
|
||||||
if (!(try child_type.hasRuntimeBitsAdvanced(false, opt_sema))) {
|
if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
|
||||||
|
else => |e| return e,
|
||||||
|
})) {
|
||||||
return AbiAlignmentAdvanced{ .scalar = 1 };
|
return AbiAlignmentAdvanced{ .scalar = 1 };
|
||||||
}
|
}
|
||||||
return child_type.abiAlignmentAdvanced(target, strat);
|
return child_type.abiAlignmentAdvanced(target, strat);
|
||||||
|
|
@ -2990,7 +2998,10 @@ pub const Type = extern union {
|
||||||
const code_align = abiAlignment(Type.anyerror, target);
|
const code_align = abiAlignment(Type.anyerror, target);
|
||||||
switch (strat) {
|
switch (strat) {
|
||||||
.eager, .sema => {
|
.eager, .sema => {
|
||||||
if (!(try data.payload.hasRuntimeBitsAdvanced(false, opt_sema))) {
|
if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
|
||||||
|
else => |e| return e,
|
||||||
|
})) {
|
||||||
return AbiAlignmentAdvanced{ .scalar = code_align };
|
return AbiAlignmentAdvanced{ .scalar = code_align };
|
||||||
}
|
}
|
||||||
return AbiAlignmentAdvanced{ .scalar = @max(
|
return AbiAlignmentAdvanced{ .scalar = @max(
|
||||||
|
|
@ -3044,7 +3055,10 @@ pub const Type = extern union {
|
||||||
const fields = ty.structFields();
|
const fields = ty.structFields();
|
||||||
var big_align: u32 = 0;
|
var big_align: u32 = 0;
|
||||||
for (fields.values()) |field| {
|
for (fields.values()) |field| {
|
||||||
if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;
|
if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
|
||||||
|
else => |e| return e,
|
||||||
|
})) continue;
|
||||||
|
|
||||||
const field_align = if (field.abi_align != 0)
|
const field_align = if (field.abi_align != 0)
|
||||||
field.abi_align
|
field.abi_align
|
||||||
|
|
@ -3161,7 +3175,10 @@ pub const Type = extern union {
|
||||||
var max_align: u32 = 0;
|
var max_align: u32 = 0;
|
||||||
if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
|
if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
|
||||||
for (union_obj.fields.values()) |field| {
|
for (union_obj.fields.values()) |field| {
|
||||||
if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;
|
if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
|
||||||
|
else => |e| return e,
|
||||||
|
})) continue;
|
||||||
|
|
||||||
const field_align = if (field.abi_align != 0)
|
const field_align = if (field.abi_align != 0)
|
||||||
field.abi_align
|
field.abi_align
|
||||||
|
|
|
||||||
|
|
@ -1911,7 +1911,11 @@ pub const Value = extern union {
|
||||||
|
|
||||||
.lazy_align => {
|
.lazy_align => {
|
||||||
const ty = lhs.castTag(.lazy_align).?.data;
|
const ty = lhs.castTag(.lazy_align).?.data;
|
||||||
if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {
|
const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
|
||||||
|
if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
}) {
|
||||||
return .gt;
|
return .gt;
|
||||||
} else {
|
} else {
|
||||||
return .eq;
|
return .eq;
|
||||||
|
|
@ -1919,7 +1923,11 @@ pub const Value = extern union {
|
||||||
},
|
},
|
||||||
.lazy_size => {
|
.lazy_size => {
|
||||||
const ty = lhs.castTag(.lazy_size).?.data;
|
const ty = lhs.castTag(.lazy_size).?.data;
|
||||||
if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {
|
const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
|
||||||
|
if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
|
||||||
|
error.NeedLazy => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
}) {
|
||||||
return .gt;
|
return .gt;
|
||||||
} else {
|
} else {
|
||||||
return .eq;
|
return .eq;
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,15 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||||
return wrap(call_inst);
|
return wrap(call_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
|
||||||
|
if (isa<Function>(unwrap(Val))) {
|
||||||
|
unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
|
||||||
|
} else {
|
||||||
|
unwrap<CallInst>(Val)->addAttributeAtIndex(Idx, unwrap(A));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
||||||
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
|
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
|
||||||
{
|
{
|
||||||
|
|
@ -1065,12 +1074,21 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val) {
|
void ZigLLVMAddByValAttr(LLVMValueRef Val, unsigned ArgNo, LLVMTypeRef type_val) {
|
||||||
Function *func = unwrap<Function>(fn_ref);
|
if (isa<Function>(unwrap(Val))) {
|
||||||
AttrBuilder attr_builder(func->getContext());
|
Function *func = unwrap<Function>(Val);
|
||||||
Type *llvm_type = unwrap<Type>(type_val);
|
AttrBuilder attr_builder(func->getContext());
|
||||||
attr_builder.addByValAttr(llvm_type);
|
Type *llvm_type = unwrap<Type>(type_val);
|
||||||
func->addParamAttrs(ArgNo, attr_builder);
|
attr_builder.addByValAttr(llvm_type);
|
||||||
|
func->addParamAttrs(ArgNo, attr_builder);
|
||||||
|
} else {
|
||||||
|
CallInst *call = unwrap<CallInst>(Val);
|
||||||
|
AttrBuilder attr_builder(call->getContext());
|
||||||
|
Type *llvm_type = unwrap<Type>(type_val);
|
||||||
|
attr_builder.addByValAttr(llvm_type);
|
||||||
|
// NOTE: +1 here since index 0 refers to the return value
|
||||||
|
call->addAttributeAtIndex(ArgNo + 1, attr_builder.getAttribute(Attribute::ByVal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {
|
void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef functio
|
||||||
LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC,
|
LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC,
|
||||||
enum ZigLLVM_CallAttr attr, const char *Name);
|
enum ZigLLVM_CallAttr attr, const char *Name);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A);
|
||||||
|
|
||||||
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
||||||
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
|
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1118,3 +1118,12 @@ test "ambiguous reference error ignores current declaration" {
|
||||||
};
|
};
|
||||||
try expect(S.b.foo == 666);
|
try expect(S.b.foo == 666);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "pointer to zero sized global is mutable" {
|
||||||
|
const S = struct {
|
||||||
|
const Thing = struct {};
|
||||||
|
|
||||||
|
var thing: Thing = undefined;
|
||||||
|
};
|
||||||
|
try expect(@TypeOf(&S.thing) == *S.Thing);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1429,3 +1429,11 @@ test "peer type resolution of function pointer and function body" {
|
||||||
try expect(@TypeOf(a, b) == *const fn () u32);
|
try expect(@TypeOf(a, b) == *const fn () u32);
|
||||||
try expect(@TypeOf(b, a) == *const fn () u32);
|
try expect(@TypeOf(b, a) == *const fn () u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "cast typed undefined to int" {
|
||||||
|
comptime {
|
||||||
|
const a: u16 = undefined;
|
||||||
|
const b: u8 = a;
|
||||||
|
_ = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -565,3 +565,10 @@ test "typeInfo resolves usingnamespace declarations" {
|
||||||
try expect(@typeInfo(B).Struct.decls.len == 2);
|
try expect(@typeInfo(B).Struct.decls.len == 2);
|
||||||
//a
|
//a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "value from struct @typeInfo default_value can be loaded at comptime" {
|
||||||
|
comptime {
|
||||||
|
const a = @typeInfo(@TypeOf(.{ .foo = @as(u8, 1) })).Struct.fields[0].default_value;
|
||||||
|
try expect(@ptrCast(*const u8, a).* == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -833,3 +833,41 @@ struct PD zig_ret_PD();
|
||||||
int c_assert_ret_PD(){
|
int c_assert_ret_PD(){
|
||||||
return c_assert_PD(zig_ret_PD());
|
return c_assert_PD(zig_ret_PD());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ByRef {
|
||||||
|
int val;
|
||||||
|
int arr[15];
|
||||||
|
};
|
||||||
|
struct ByRef c_modify_by_ref_param(struct ByRef in) {
|
||||||
|
in.val = 42;
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ByVal {
|
||||||
|
struct {
|
||||||
|
unsigned long x;
|
||||||
|
unsigned long y;
|
||||||
|
unsigned long z;
|
||||||
|
} origin;
|
||||||
|
struct {
|
||||||
|
unsigned long width;
|
||||||
|
unsigned long height;
|
||||||
|
unsigned long depth;
|
||||||
|
} size;
|
||||||
|
};
|
||||||
|
|
||||||
|
void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *d, unsigned long e) {
|
||||||
|
assert_or_panic((intptr_t)a == 1);
|
||||||
|
assert_or_panic((intptr_t)b == 2);
|
||||||
|
|
||||||
|
assert_or_panic(in.origin.x == 9);
|
||||||
|
assert_or_panic(in.origin.y == 10);
|
||||||
|
assert_or_panic(in.origin.z == 11);
|
||||||
|
assert_or_panic(in.size.width == 12);
|
||||||
|
assert_or_panic(in.size.height == 13);
|
||||||
|
assert_or_panic(in.size.depth == 14);
|
||||||
|
|
||||||
|
assert_or_panic(c == 3);
|
||||||
|
assert_or_panic((intptr_t)d == 4);
|
||||||
|
assert_or_panic(e == 5);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -917,8 +917,6 @@ test "CFF: C passes to Zig" {
|
||||||
try expectOk(c_send_CFF());
|
try expectOk(c_send_CFF());
|
||||||
}
|
}
|
||||||
test "CFF: C returns to Zig" {
|
test "CFF: C returns to Zig" {
|
||||||
// segfault on aarch64 and mips
|
|
||||||
if (builtin.target.cpu.arch == .aarch64) return error.SkipZigTest;
|
|
||||||
if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
|
if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
|
||||||
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
|
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
|
if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
|
||||||
|
|
@ -990,3 +988,47 @@ pub export fn zig_assert_PD(lv: PD) c_int {
|
||||||
if (err != 0) std.debug.print("Received {}", .{lv});
|
if (err != 0) std.debug.print("Received {}", .{lv});
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ByRef = extern struct {
|
||||||
|
val: c_int,
|
||||||
|
arr: [15]c_int,
|
||||||
|
};
|
||||||
|
extern fn c_modify_by_ref_param(ByRef) ByRef;
|
||||||
|
|
||||||
|
test "C function modifies by ref param" {
|
||||||
|
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
|
||||||
|
try expect(res.val == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByVal = extern struct {
|
||||||
|
origin: extern struct {
|
||||||
|
x: c_ulong,
|
||||||
|
y: c_ulong,
|
||||||
|
z: c_ulong,
|
||||||
|
},
|
||||||
|
size: extern struct {
|
||||||
|
width: c_ulong,
|
||||||
|
height: c_ulong,
|
||||||
|
depth: c_ulong,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
|
||||||
|
test "C function that takes byval struct called via function pointer" {
|
||||||
|
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
|
|
||||||
|
var fn_ptr = &c_func_ptr_byval;
|
||||||
|
fn_ptr(
|
||||||
|
@intToPtr(*anyopaque, 1),
|
||||||
|
@intToPtr(*anyopaque, 2),
|
||||||
|
ByVal{
|
||||||
|
.origin = .{ .x = 9, .y = 10, .z = 11 },
|
||||||
|
.size = .{ .width = 12, .height = 13, .depth = 14 },
|
||||||
|
},
|
||||||
|
@as(c_ulong, 3),
|
||||||
|
@intToPtr(*anyopaque, 4),
|
||||||
|
@as(c_ulong, 5),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,14 @@ comptime {
|
||||||
var a: A = A{};
|
var a: A = A{};
|
||||||
_ = a;
|
_ = a;
|
||||||
}
|
}
|
||||||
|
pub export fn entry1() void {
|
||||||
|
var bla: V = .{ 1, 2, 3, 4 };
|
||||||
|
_ = bla;
|
||||||
|
}
|
||||||
|
pub export fn entry2() void {
|
||||||
|
var bla: A = .{ 1, 2, 3, 4 };
|
||||||
|
_ = bla;
|
||||||
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage2
|
// backend=stage2
|
||||||
|
|
@ -25,3 +33,5 @@ comptime {
|
||||||
// :8:17: error: expected 8 vector elements; found 0
|
// :8:17: error: expected 8 vector elements; found 0
|
||||||
// :12:17: error: expected 8 array elements; found 1
|
// :12:17: error: expected 8 array elements; found 1
|
||||||
// :16:17: error: expected 8 array elements; found 0
|
// :16:17: error: expected 8 array elements; found 0
|
||||||
|
// :20:19: error: expected 8 vector elements; found 4
|
||||||
|
// :24:19: error: expected 8 array elements; found 4
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
var a: u32 = 2;
|
||||||
|
const b = a;
|
||||||
|
pub export fn entry() void {
|
||||||
|
_ = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :2:11: error: unable to resolve comptime value
|
||||||
|
// :2:11: note: global variable initializer must be comptime-known
|
||||||
9
test/cases/compile_errors/inttoptr_non_ptr_type.zig
Normal file
9
test/cases/compile_errors/inttoptr_non_ptr_type.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
pub export fn entry() void {
|
||||||
|
_ = @intToPtr(i32, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :2:19: error: expected pointer type, found 'i32'
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
const S = struct {
|
||||||
|
a: u32,
|
||||||
|
b: comptime_int,
|
||||||
|
fn init() S {
|
||||||
|
return .{ .a = 1 };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
comptime {
|
||||||
|
_ = S.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :5:17: error: missing struct field: b
|
||||||
|
// :1:11: note: struct 'tmp.S' declared here
|
||||||
|
// :9:15: note: called from here
|
||||||
Loading…
Add table
Reference in a new issue