diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-12-18 16:24:13 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-18 16:24:13 -0500 |
| commit | aca9c74e80e106309b9783ff251ab0cdd3fb9626 (patch) | |
| tree | 16c65995ac6d3b434af61c4cd61a191b81dd93a0 /src/Sema.zig | |
| parent | d93edadead45e447e6bc16c0934a3031a06d0fd8 (diff) | |
| parent | 9bb1104e373dec192fb2a22d48b023330ddbaeae (diff) | |
| download | zig-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.zig | 120 |
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]; |
