aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-07-28 21:03:10 +0300
committerVeikka Tuominen <git@vexu.eu>2022-08-01 23:59:40 +0300
commite47706f34454c46dd00fe10fdf9252657117a00d (patch)
treeef7ab64fbe9d3123004b3fe94781bfcabc8325fa /src/Sema.zig
parentf1768b40b2468d63355c8cf83d3614ae23a54317 (diff)
downloadzig-e47706f34454c46dd00fe10fdf9252657117a00d.tar.gz
zig-e47706f34454c46dd00fe10fdf9252657117a00d.zip
Sema: validate packed struct field types
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig156
1 files changed, 127 insertions, 29 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 22d0c572fc..71ab59d7f9 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -5049,13 +5049,13 @@ pub fn analyzeExport(
try mod.ensureDeclAnalyzed(exported_decl_index);
const exported_decl = mod.declPtr(exported_decl_index);
- if (!(try sema.validateExternType(exported_decl.ty, .other))) {
+ if (!sema.validateExternType(exported_decl.ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), exported_decl.ty, .other);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other);
try sema.addDeclaredHereNote(msg, exported_decl.ty);
break :msg msg;
@@ -7634,7 +7634,7 @@ fn funcCommon(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !(try sema.validateExternType(return_type, .ret_ty))) {
+ if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !sema.validateExternType(return_type, .ret_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
return_type.fmt(sema.mod), @tagName(cc_workaround),
@@ -7642,7 +7642,7 @@ fn funcCommon(
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty);
+ try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty);
try sema.addDeclaredHereNote(msg, return_type);
break :msg msg;
@@ -7830,7 +7830,7 @@ fn analyzeParameter(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- if (!Type.fnCallingConventionAllowsZigTypes(cc) and !(try sema.validateExternType(param.ty, .param_ty))) {
+ if (!Type.fnCallingConventionAllowsZigTypes(cc) and !sema.validateExternType(param.ty, .param_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
param.ty.fmt(sema.mod), @tagName(cc),
@@ -7838,7 +7838,7 @@ fn analyzeParameter(
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(block, param_src, msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty);
+ try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty);
try sema.addDeclaredHereNote(msg, param.ty);
break :msg msg;
@@ -14866,13 +14866,13 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
} else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) {
return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
} else if (inst_data.size == .C) {
- if (!(try sema.validateExternType(elem_ty, .other))) {
+ if (!sema.validateExternType(elem_ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(block, elem_ty_src, msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other);
+ try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other);
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
@@ -15950,13 +15950,13 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
} else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) {
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
} else if (ptr_size == .C) {
- if (!(try sema.validateExternType(elem_ty, .other))) {
+ if (!sema.validateExternType(elem_ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), elem_ty, .other);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other);
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
@@ -19736,7 +19736,7 @@ const ExternPosition = enum {
/// Returns true if `ty` is allowed in extern types.
/// Does *NOT* require `ty` to be resolved in any way.
-fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileError!bool {
+fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool {
switch (ty.zigTypeTag()) {
.Type,
.ComptimeFloat,
@@ -19781,8 +19781,6 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileEr
fn explainWhyTypeIsNotExtern(
sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
msg: *Module.ErrorMsg,
src_loc: Module.SrcLoc,
ty: Type,
@@ -19826,7 +19824,7 @@ fn explainWhyTypeIsNotExtern(
var buf: Type.Payload.Bits = undefined;
const tag_ty = ty.intTagType(&buf);
try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
- try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, tag_ty, position);
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
},
.Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}),
.Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}),
@@ -19836,13 +19834,87 @@ fn explainWhyTypeIsNotExtern(
} else if (position == .param_ty) {
return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
}
- try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position);
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position);
},
- .Vector => try sema.explainWhyTypeIsNotExtern(block, src, msg, src_loc, ty.elemType2(), position),
+ .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), position),
.Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
}
}
+/// Returns true if `ty` is allowed in packed types.
+/// Does *NOT* require `ty` to be resolved in any way.
+fn validatePackedType(ty: Type) bool {
+ switch (ty.zigTypeTag()) {
+ .Type,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .EnumLiteral,
+ .Undefined,
+ .Null,
+ .ErrorUnion,
+ .ErrorSet,
+ .BoundFn,
+ .Frame,
+ .NoReturn,
+ .Opaque,
+ .AnyFrame,
+ .Fn,
+ .Array,
+ .Optional,
+ => return false,
+ .Void,
+ .Bool,
+ .Float,
+ .Pointer,
+ .Int,
+ .Vector,
+ .Enum,
+ => return true,
+ .Struct, .Union => return ty.containerLayout() == .Packed,
+ }
+}
+
+fn explainWhyTypeIsNotPacked(
+ sema: *Sema,
+ msg: *Module.ErrorMsg,
+ src_loc: Module.SrcLoc,
+ ty: Type,
+) CompileError!void {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag()) {
+ .Void,
+ .Bool,
+ .Float,
+ .Pointer,
+ .Int,
+ .Vector,
+ .Enum,
+ => return,
+ .Type,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .EnumLiteral,
+ .Undefined,
+ .Null,
+ .BoundFn,
+ .Frame,
+ .NoReturn,
+ .Opaque,
+ .ErrorUnion,
+ .ErrorSet,
+ .AnyFrame,
+ .Optional,
+ .Array,
+ => try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
+ .Fn => {
+ try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
+ try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
+ },
+ .Struct => try mod.errNoteNonLazy(src_loc, msg, "only packed structs layout are allowed in packed types", .{}),
+ .Union => try mod.errNoteNonLazy(src_loc, msg, "only packed unions layout are allowed in packed types", .{}),
+ }
+}
+
pub const PanicId = enum {
unreach,
unwrap_null,
@@ -26919,28 +26991,41 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
const field = &struct_obj.fields.values()[i];
field.ty = try field_ty.copy(decl_arena_allocator);
- if (struct_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
+ if (field_ty.zigTypeTag() == .Opaque) {
+ const msg = msg: {
+ const tree = try sema.getAstTree(&block_scope);
+ const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
+ const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
+ errdefer msg.destroy(sema.gpa);
+
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(&block_scope, msg);
+ }
+ if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsNotExtern(&block_scope, fields_src, msg, fields_src.toSrcLoc(decl), field.ty, .other);
+ try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .other);
try sema.addDeclaredHereNote(msg, field.ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- if (field_ty.zigTypeTag() == .Opaque) {
+ } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
- const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
- const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
+ const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);
+ const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, field_ty);
+ try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field.ty);
+
+ try sema.addDeclaredHereNote(msg, field.ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(&block_scope, msg);
@@ -27243,27 +27328,40 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
}
- if (union_obj.layout == .Extern and !(try sema.validateExternType(field_ty, .union_field))) {
+ if (field_ty.zigTypeTag() == .Opaque) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
- const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsNotExtern(&block_scope, field_src, msg, field_src.toSrcLoc(decl), field_ty, .union_field);
-
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(&block_scope, msg);
}
- if (field_ty.zigTypeTag() == .Opaque) {
+ if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
- const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
+ const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, field_src.toSrcLoc(decl), field_ty, .union_field);
+
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(&block_scope, msg);
+ } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
+ const msg = msg: {
+ const tree = try sema.getAstTree(&block_scope);
+ const fields_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
+ const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+
+ try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field_ty);
+
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
};