mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:24:49 +01:00
Sema: defer extern function type validation to declaration or call
Because of packed structs, checking whether a type is extern-compatible requires that its layout be resolved. For functions to do this validation as soon as the function type is created would lead to dependency loops in cases like '*const fn (*@This()) void callconv(.c)`. Therefore, when creating a function *type*, we no longer perform this check immediately, instead waiting until the function is called.
This commit is contained in:
parent
c503999d22
commit
07445c1f9f
3 changed files with 156 additions and 109 deletions
258
src/Sema.zig
258
src/Sema.zig
|
|
@ -5747,6 +5747,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
|||
}
|
||||
|
||||
const export_ty = ptr_ty.childType(zcu);
|
||||
try sema.ensureLayoutResolved(export_ty, src, .@"export");
|
||||
if (!export_ty.validateExtern(.other, zcu)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
|
||||
|
|
@ -6749,6 +6750,37 @@ fn analyzeCall(
|
|||
} else func_src;
|
||||
|
||||
const func_ty_info = zcu.typeToFunc(func_ty).?;
|
||||
|
||||
for (func_ty_info.param_types.get(ip), 0..) |param_ty_ip, param_index| {
|
||||
const arg_src = args_info.argSrc(block, param_index);
|
||||
try sema.ensureLayoutResolved(.fromInterned(param_ty_ip), arg_src, .init);
|
||||
}
|
||||
try sema.ensureLayoutResolved(.fromInterned(func_ty_info.return_type), func_ret_ty_src, .return_type);
|
||||
try sema.validateResolvedFuncType(
|
||||
block,
|
||||
func_ty_info.cc,
|
||||
func_ty_info.param_types.get(ip),
|
||||
.fromInterned(func_ty_info.return_type),
|
||||
func_src,
|
||||
maybe_func_inst,
|
||||
);
|
||||
|
||||
if (!callConvIsCallable(func_ty_info.cc)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(
|
||||
func_src,
|
||||
"unable to call function with calling convention '{s}'",
|
||||
.{@tagName(func_ty_info.cc)},
|
||||
);
|
||||
errdefer msg.destroy(gpa);
|
||||
if (maybe_func_inst) |func_inst| try sema.errNote(.{
|
||||
.base_node_inst = func_inst,
|
||||
.offset = .nodeOffset(.zero),
|
||||
}, msg, "function declared here", .{});
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: {
|
||||
for (func_ty_info.param_types.get(ip)) |param_ty| {
|
||||
if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true;
|
||||
|
|
@ -6771,22 +6803,6 @@ fn analyzeCall(
|
|||
break :generic false;
|
||||
};
|
||||
|
||||
if (!callConvIsCallable(func_ty_info.cc)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(
|
||||
func_src,
|
||||
"unable to call function with calling convention '{s}'",
|
||||
.{@tagName(func_ty_info.cc)},
|
||||
);
|
||||
errdefer msg.destroy(gpa);
|
||||
if (maybe_func_inst) |func_inst| try sema.errNote(.{
|
||||
.base_node_inst = func_inst,
|
||||
.offset = .nodeOffset(.zero),
|
||||
}, msg, "function declared here", .{});
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
// We need this value in a few code paths.
|
||||
const callee_val = try sema.resolveDefinedValue(block, call_src, callee);
|
||||
// If the callee is a comptime-known *non-extern* function, `func_val` is populated.
|
||||
|
|
@ -8755,11 +8771,12 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
|
|||
}
|
||||
}
|
||||
|
||||
fn checkParamTypeCommon(
|
||||
fn checkParamType(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
param_idx: u32,
|
||||
param_ty: Type,
|
||||
param_is_comptime: bool,
|
||||
param_is_noalias: bool,
|
||||
param_src: LazySrcLoc,
|
||||
cc: std.builtin.CallingConvention,
|
||||
|
|
@ -8774,29 +8791,22 @@ fn checkParamTypeCommon(
|
|||
opaque_str, param_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!param_ty.isGenericPoison() and
|
||||
!target_util.fnCallConvAllowsZigTypes(cc) and
|
||||
!param_ty.validateExtern(.param_ty, zcu))
|
||||
{
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
|
||||
param_ty.fmt(pt), @tagName(cc),
|
||||
});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
if (!target_util.fnCallConvAllowsZigTypes(cc)) {
|
||||
if (param_is_comptime) {
|
||||
return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{t}'", .{cc});
|
||||
}
|
||||
if (param_ty.isGenericPoison()) {
|
||||
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{t}'", .{cc});
|
||||
}
|
||||
// The `validateExtern` check happens later, in `validateResolvedFuncType`.
|
||||
}
|
||||
switch (cc) {
|
||||
.x86_64_interrupt, .x86_interrupt => {
|
||||
const err_code_size = target.ptrBitWidth();
|
||||
switch (param_idx) {
|
||||
0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
|
||||
1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
|
||||
else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }),
|
||||
0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{t}' calling convention must be a pointer type", .{cc}),
|
||||
1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{t}' calling convention must be a {d}-bit integer", .{ cc, err_code_size }),
|
||||
else => return sema.fail(block, param_src, "'{t}' calling convention supports up to 2 parameters, found {d}", .{ cc, param_idx + 1 }),
|
||||
}
|
||||
},
|
||||
.arc_interrupt,
|
||||
|
|
@ -8812,7 +8822,7 @@ fn checkParamTypeCommon(
|
|||
.m68k_interrupt,
|
||||
.msp430_interrupt,
|
||||
.avr_signal,
|
||||
=> return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
|
||||
=> return sema.fail(block, param_src, "parameters are not allowed with '{t}' calling convention", .{cc}),
|
||||
else => {},
|
||||
}
|
||||
if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) {
|
||||
|
|
@ -8820,7 +8830,7 @@ fn checkParamTypeCommon(
|
|||
}
|
||||
}
|
||||
|
||||
fn checkReturnTypeAndCallConvCommon(
|
||||
fn checkReturnTypeAndCallConv(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
bare_ret_ty: Type,
|
||||
|
|
@ -8834,7 +8844,6 @@ fn checkReturnTypeAndCallConvCommon(
|
|||
) CompileError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
if (opt_varargs_src) |varargs_src| {
|
||||
try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv");
|
||||
}
|
||||
|
|
@ -8848,21 +8857,14 @@ fn checkReturnTypeAndCallConvCommon(
|
|||
opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!bare_ret_ty.isGenericPoison() and
|
||||
!target_util.fnCallConvAllowsZigTypes(@"callconv") and
|
||||
(inferred_error_set or !bare_ret_ty.validateExtern(.ret_ty, zcu)))
|
||||
{
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
|
||||
ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
if (!inferred_error_set) {
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty);
|
||||
try sema.addDeclaredHereNote(msg, bare_ret_ty);
|
||||
}
|
||||
break :msg msg;
|
||||
});
|
||||
if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
|
||||
if (inferred_error_set) {
|
||||
return sema.fail(block, ret_ty_src, "return type '!{f}' not allowed in function with calling convention '{t}'", .{ bare_ret_ty.fmt(pt), @"callconv" });
|
||||
}
|
||||
if (bare_ret_ty.isGenericPoison()) {
|
||||
return sema.fail(block, ret_ty_src, "generic return type not allowed in function with calling convention '{t}'", .{@"callconv"});
|
||||
}
|
||||
// The `validateExtern` check happens later, in `validateResolvedFuncType`.
|
||||
}
|
||||
validate_incoming_stack_align: {
|
||||
const a: u64 = switch (@"callconv") {
|
||||
|
|
@ -8897,7 +8899,7 @@ fn checkReturnTypeAndCallConvCommon(
|
|||
else => false,
|
||||
};
|
||||
if (!ret_ok) {
|
||||
return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")});
|
||||
return sema.fail(block, ret_ty_src, "function with calling convention '{t}' must return 'void' or 'noreturn'", .{@"callconv"});
|
||||
}
|
||||
},
|
||||
.@"inline" => if (is_noinline) {
|
||||
|
|
@ -8918,18 +8920,76 @@ fn checkReturnTypeAndCallConvCommon(
|
|||
}
|
||||
}
|
||||
};
|
||||
return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{
|
||||
@tagName(@"callconv"),
|
||||
ArchListFormatter{ .archs = allowed_archs },
|
||||
return sema.fail(block, callconv_src, "calling convention '{t}' only available on architectures {f}", .{
|
||||
@"callconv", ArchListFormatter{ .archs = allowed_archs },
|
||||
});
|
||||
},
|
||||
.bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
|
||||
@tagName(@"callconv"),
|
||||
@tagName(bad_backend),
|
||||
.bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{t}' not supported by compiler backend '{t}'", .{
|
||||
@"callconv", bad_backend,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// To avoid forcing type layout resolution too quickly, some validation of function types cannot be
|
||||
/// performed when the type is first constructed, and instead must happen when either (a) a function
|
||||
/// with that type is declared, or (b) a function with that type is called. That validation is
|
||||
/// handled here.
|
||||
///
|
||||
/// Asserts that all parameter types and return types have their layout fully resolved.
|
||||
fn validateResolvedFuncType(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
@"callconv": std.builtin.CallingConvention,
|
||||
param_types: []const InternPool.Index,
|
||||
ret_ty: Type,
|
||||
src: LazySrcLoc,
|
||||
maybe_func_decl_inst: ?InternPool.TrackedInst.Index,
|
||||
) SemaError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.comp.gpa;
|
||||
if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
|
||||
// Check that all parameter types are extern-compatible.
|
||||
for (param_types, 0..) |param_ty_ip, param_index| {
|
||||
const param_ty: Type = .fromInterned(param_ty_ip);
|
||||
if (!param_ty.validateExtern(.param_ty, zcu)) {
|
||||
const param_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
|
||||
.base_node_inst = inst,
|
||||
.offset = .{ .fn_proto_param = .{
|
||||
.fn_proto_node_offset = .zero,
|
||||
.param_index = @intCast(param_index),
|
||||
} },
|
||||
} else src;
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{t}'", .{
|
||||
param_ty.fmt(pt), @"callconv",
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
}
|
||||
// Check that the return type is extern-compatible.
|
||||
if (!ret_ty.validateExtern(.ret_ty, zcu)) {
|
||||
const ret_ty_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
|
||||
.base_node_inst = inst,
|
||||
.offset = .{ .node_offset_fn_type_ret_ty = .zero },
|
||||
} else src;
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{t}'", .{
|
||||
ret_ty.fmt(pt), @"callconv",
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, ret_ty, .ret_ty);
|
||||
try sema.addDeclaredHereNote(msg, ret_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool {
|
||||
return switch (cc) {
|
||||
.naked,
|
||||
|
|
@ -9022,6 +9082,7 @@ fn funcCommon(
|
|||
const io = comp.io;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const src = block.nodeOffset(src_node_offset);
|
||||
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
|
||||
const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
|
||||
|
||||
|
|
@ -9036,27 +9097,21 @@ fn funcCommon(
|
|||
.fn_proto_node_offset = src_node_offset,
|
||||
.param_index = @intCast(i),
|
||||
} });
|
||||
const param_ty_generic = param_ty.isGenericPoison();
|
||||
if (param_is_comptime) {
|
||||
comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error
|
||||
}
|
||||
if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc)) {
|
||||
return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
|
||||
}
|
||||
if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
|
||||
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
|
||||
}
|
||||
try sema.checkParamTypeCommon(
|
||||
try sema.checkParamType(
|
||||
block,
|
||||
@intCast(i),
|
||||
param_ty,
|
||||
param_is_comptime,
|
||||
is_noalias,
|
||||
param_src,
|
||||
cc,
|
||||
);
|
||||
}
|
||||
|
||||
try sema.checkReturnTypeAndCallConvCommon(
|
||||
try sema.checkReturnTypeAndCallConv(
|
||||
block,
|
||||
bare_return_type,
|
||||
ret_ty_src,
|
||||
|
|
@ -9072,9 +9127,29 @@ fn funcCommon(
|
|||
|
||||
const param_types = block.params.items(.ty);
|
||||
|
||||
if (has_body) {
|
||||
for (param_types, 0..) |param_ty_ip, param_index| {
|
||||
const param_ty: Type = .fromInterned(param_ty_ip);
|
||||
const param_src = block.src(.{ .fn_proto_param = .{
|
||||
.fn_proto_node_offset = src_node_offset,
|
||||
.param_index = @intCast(param_index),
|
||||
} });
|
||||
try sema.ensureLayoutResolved(param_ty, param_src, .parameter);
|
||||
}
|
||||
try sema.ensureLayoutResolved(bare_return_type, ret_ty_src, .return_type);
|
||||
try sema.validateResolvedFuncType(
|
||||
block,
|
||||
cc,
|
||||
param_types,
|
||||
bare_return_type,
|
||||
src,
|
||||
ip.getNav(sema.owner.unwrap().nav_val).srcInst(ip),
|
||||
);
|
||||
}
|
||||
|
||||
if (inferred_error_set) {
|
||||
assert(has_body);
|
||||
const func_val: Value = .fromInterned(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
|
||||
return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
|
||||
.param_types = param_types,
|
||||
|
|
@ -9091,8 +9166,6 @@ fn funcCommon(
|
|||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
.rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
|
||||
}));
|
||||
try sema.ensureLayoutResolved(func_val.typeOf(zcu), ret_ty_src, .return_type);
|
||||
return .fromValue(func_val);
|
||||
}
|
||||
|
||||
const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{
|
||||
|
|
@ -9106,7 +9179,6 @@ fn funcCommon(
|
|||
});
|
||||
|
||||
if (has_body) {
|
||||
try sema.ensureLayoutResolved(.fromInterned(func_ty), ret_ty_src, .return_type);
|
||||
return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
.ty = func_ty,
|
||||
|
|
@ -18256,19 +18328,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||
}
|
||||
} else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
|
||||
return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
|
||||
} else if (inst_data.size == .c) {
|
||||
if (!elem_ty.validateExtern(.other, zcu)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (host_size != 0) {
|
||||
|
|
@ -19800,16 +19859,6 @@ fn zirReifyPointer(
|
|||
else => {},
|
||||
}
|
||||
|
||||
if (size == .c and !elem_ty.validateExtern(.other, zcu)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
const sentinel_ty = try pt.optionalType(elem_ty.toIntern());
|
||||
const sentinel_uncoerced = sema.resolveInst(extra.sentinel);
|
||||
const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src);
|
||||
|
|
@ -19898,10 +19947,11 @@ fn zirReifyFn(
|
|||
try param_attrs_arr.elemValue(pt, param_idx),
|
||||
std.builtin.Type.Fn.Param.Attributes,
|
||||
);
|
||||
try sema.checkParamTypeCommon(
|
||||
try sema.checkParamType(
|
||||
block,
|
||||
@intCast(param_idx),
|
||||
param_ty,
|
||||
false,
|
||||
param_attrs.@"noalias",
|
||||
param_types_src,
|
||||
fn_attrs.@"callconv",
|
||||
|
|
@ -19919,7 +19969,7 @@ fn zirReifyFn(
|
|||
try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv");
|
||||
}
|
||||
|
||||
try sema.checkReturnTypeAndCallConvCommon(
|
||||
try sema.checkReturnTypeAndCallConv(
|
||||
block,
|
||||
ret_ty,
|
||||
ret_ty_src,
|
||||
|
|
@ -19929,9 +19979,6 @@ fn zirReifyFn(
|
|||
false,
|
||||
false,
|
||||
);
|
||||
if (ret_ty.comptimeOnly(zcu)) {
|
||||
return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
|
||||
}
|
||||
|
||||
return .fromIntern(try ip.getFuncType(gpa, io, pt.tid, .{
|
||||
.param_types = param_types_ip,
|
||||
|
|
@ -20615,7 +20662,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
|
|||
|
||||
const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
|
||||
const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
|
||||
|
||||
try sema.ensureLayoutResolved(arg_ty, ty_src, .parameter);
|
||||
if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
|
||||
|
|
@ -24639,13 +24686,12 @@ fn zirBuiltinExtern(
|
|||
return sema.fail(block, ty_src, "expected (optional) pointer", .{});
|
||||
}
|
||||
if (!ty.validateExtern(.other, zcu)) {
|
||||
const msg = msg: {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
});
|
||||
}
|
||||
|
||||
const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
|
||||
|
|
@ -25034,7 +25080,7 @@ pub fn explainWhyTypeIsNotExtern(
|
|||
src_loc: LazySrcLoc,
|
||||
ty: Type,
|
||||
position: Type.ExternPosition,
|
||||
) CompileError!void {
|
||||
) SemaError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
switch (ty.zigTypeTag(zcu)) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ pub const LayoutResolveReason = enum {
|
|||
type_info,
|
||||
align_check,
|
||||
bit_ptr_child,
|
||||
@"export",
|
||||
builtin_type,
|
||||
|
||||
/// Written after string: "while resolving type 'T' "
|
||||
|
|
@ -56,6 +57,7 @@ pub const LayoutResolveReason = enum {
|
|||
.type_info => "for type information query here",
|
||||
.align_check => "for alignment check here",
|
||||
.bit_ptr_child => "for bit size check here",
|
||||
.@"export" => "for export here",
|
||||
.builtin_type => "from 'std.builtin'",
|
||||
// zig fmt: on
|
||||
};
|
||||
|
|
@ -276,7 +278,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
|
|||
assert(!field_ty.isGenericPoison());
|
||||
const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
|
||||
try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
|
||||
|
||||
if (field_ty.zigTypeTag(zcu) == .@"opaque") {
|
||||
return sema.failWithOwnedErrorMsg(&block, msg: {
|
||||
const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
|
||||
|
|
@ -286,7 +287,6 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
|
|||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) {
|
||||
return sema.failWithOwnedErrorMsg(&block, msg: {
|
||||
const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
|
|
|
|||
|
|
@ -3055,9 +3055,10 @@ pub const ExternPosition = enum {
|
|||
};
|
||||
|
||||
/// Returns true if `ty` is allowed in extern types.
|
||||
/// Does not require `ty` to be resolved in any way.
|
||||
/// Asserts that `ty` is fully resolved.
|
||||
/// Keep in sync with `Sema.explainWhyTypeIsNotExtern`.
|
||||
pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool {
|
||||
ty.assertHasLayout(zcu);
|
||||
return switch (ty.zigTypeTag(zcu)) {
|
||||
.type,
|
||||
.comptime_float,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue