aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-12-18 16:24:13 -0500
committerGitHub <noreply@github.com>2022-12-18 16:24:13 -0500
commitaca9c74e80e106309b9783ff251ab0cdd3fb9626 (patch)
tree16c65995ac6d3b434af61c4cd61a191b81dd93a0 /src/Sema.zig
parentd93edadead45e447e6bc16c0934a3031a06d0fd8 (diff)
parent9bb1104e373dec192fb2a22d48b023330ddbaeae (diff)
downloadzig-aca9c74e80e106309b9783ff251ab0cdd3fb9626.tar.gz
zig-aca9c74e80e106309b9783ff251ab0cdd3fb9626.zip
Merge pull request #13914 from Vexu/variadic
implement defining C variadic functions
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig120
1 files changed, 119 insertions, 1 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index e4f82d6438..ede4eaf0e7 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1148,6 +1148,10 @@ fn analyzeBodyInner(
.builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),
.cmpxchg => try sema.zirCmpxchg( block, extended),
.addrspace_cast => try sema.zirAddrSpaceCast( block, extended),
+ .c_va_arg => try sema.zirCVaArg( block, extended),
+ .c_va_copy => try sema.zirCVaCopy( block, extended),
+ .c_va_end => try sema.zirCVaEnd( block, extended),
+ .c_va_start => try sema.zirCVaStart( block, extended),
// zig fmt: on
.fence => {
@@ -6426,6 +6430,11 @@ fn analyzeCall(
else => unreachable,
};
if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail;
+ if (func_ty_info.is_var_args) {
+ return sema.fail(block, call_src, "{s} call of variadic function", .{
+ @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
+ });
+ }
// Analyze the ZIR. The same ZIR gets analyzed into a runtime function
// or an inlined call depending on what union tag the `label` field is
@@ -8407,6 +8416,7 @@ fn funcCommon(
) CompileError!Air.Inst.Ref {
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
+ const func_src = LazySrcLoc.nodeOffset(src_node_offset);
var is_generic = bare_return_type.tag() == .generic_poison or
alignment == null or
@@ -8414,6 +8424,15 @@ fn funcCommon(
section == .generic or
cc == null;
+ if (var_args) {
+ if (is_generic) {
+ return sema.fail(block, func_src, "generic function cannot be variadic", .{});
+ }
+ if (cc.? != .C) {
+ return sema.fail(block, cc_src, "variadic function must have 'C' calling convention", .{});
+ }
+ }
+
var destroy_fn_on_error = false;
const new_func: *Module.Fn = new_func: {
if (!has_body) break :new_func undefined;
@@ -16353,6 +16372,15 @@ fn finishCondBr(
return Air.indexToRef(block_inst);
}
+fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+ switch (ty.zigTypeTag()) {
+ .Optional, .Null, .Undefined => return,
+ .Pointer => if (ty.isPtrLikeOptional()) return,
+ else => {},
+ }
+ return sema.failWithExpectedOptionalType(block, src, ty);
+}
+
fn zirIsNonNull(
sema: *Sema,
block: *Block,
@@ -16364,6 +16392,7 @@ fn zirIsNonNull(
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
+ try sema.checkNullableType(block, src, sema.typeOf(operand));
return sema.analyzeIsNull(block, src, operand, true);
}
@@ -16378,6 +16407,7 @@ fn zirIsNonNullPtr(
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
+ try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2());
if ((try sema.resolveMaybeUndefVal(ptr)) == null) {
return block.addUnOp(.is_non_null_ptr, ptr);
}
@@ -16385,12 +16415,23 @@ fn zirIsNonNullPtr(
return sema.analyzeIsNull(block, src, loaded, true);
}
+fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+ switch (ty.zigTypeTag()) {
+ .ErrorSet, .ErrorUnion, .Undefined => return,
+ else => return sema.fail(block, src, "expected error union type, found '{}'", .{
+ ty.fmt(sema.mod),
+ }),
+ }
+}
+
fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
+ try sema.checkErrorType(block, src, sema.typeOf(operand));
return sema.analyzeIsNonErr(block, inst_data.src(), operand);
}
@@ -16401,6 +16442,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
+ try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2());
const loaded = try sema.analyzeLoad(block, src, ptr, src);
return sema.analyzeIsNonErr(block, src, loaded);
}
@@ -19020,6 +19062,79 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
});
}
+fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
+ const va_list_ty = try sema.getBuiltinType("VaList");
+ const va_list_ptr = try Type.ptr(sema.arena, sema.mod, .{
+ .pointee_type = va_list_ty,
+ .mutable = true,
+ .@"addrspace" = .generic,
+ });
+
+ const inst = try sema.resolveInst(zir_ref);
+ return sema.coerce(block, va_list_ptr, inst, src);
+}
+
+fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
+ const src = LazySrcLoc.nodeOffset(extra.node);
+ const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
+ const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
+
+ const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
+ const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
+
+ if (!try sema.validateExternType(arg_ty, .param_ty)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+
+ const src_decl = sema.mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl), arg_ty, .param_ty);
+
+ try sema.addDeclaredHereNote(msg, arg_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+
+ try sema.requireRuntimeBlock(block, src, null);
+ return block.addTyOp(.c_va_arg, arg_ty, va_list_ref);
+}
+
+fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const src = LazySrcLoc.nodeOffset(extra.node);
+ const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
+
+ const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
+ const va_list_ty = try sema.getBuiltinType("VaList");
+
+ try sema.requireRuntimeBlock(block, src, null);
+ return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref);
+}
+
+fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const src = LazySrcLoc.nodeOffset(extra.node);
+ const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
+
+ const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
+
+ try sema.requireRuntimeBlock(block, src, null);
+ return block.addUnOp(.c_va_end, va_list_ref);
+}
+
+fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
+
+ const va_list_ty = try sema.getBuiltinType("VaList");
+ try sema.requireRuntimeBlock(block, src, null);
+ return block.addInst(.{
+ .tag = .c_va_start,
+ .data = .{ .ty = va_list_ty },
+ });
+}
+
fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -21524,7 +21639,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
else => |e| return e,
};
break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
- } else std.builtin.CallingConvention.Unspecified;
+ } else if (sema.owner_decl.is_exported and has_body)
+ .C
+ else
+ .Unspecified;
const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
const body_len = sema.code.extra[extra_index];