zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 6b2274fd994edfd26db49d4a2599bbace881fd7a (tree)
parent 344f4d9bc586507c00324cd3844b9b9f778a3c65
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Sat, 18 Apr 2020 14:35:35 -0400

Merge pull request #5088 from Vexu/varargs-fix

Add error for non-exter variadic functions
Diffstat:
Msrc/analyze.cpp | 8+++++++-
Msrc/ir.cpp | 15+++++++--------
Mtest/compile_errors.zig | 24++++++++++++------------
Mtest/stage1/behavior/type_info.zig | 68+++++++++++++++++++++++++++++++++-----------------------------------
4 files changed, 59 insertions(+), 56 deletions(-)

diff --git a/src/analyze.cpp b/src/analyze.cpp @@ -3619,12 +3619,18 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { assert(tld->source_node->type == NodeTypeFnProto); is_export = tld->source_node->data.fn_proto.is_export; - if (!is_export && !tld->source_node->data.fn_proto.is_extern && + if (!tld->source_node->data.fn_proto.is_extern && tld->source_node->data.fn_proto.fn_def_node == nullptr) { add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body")); return; } + if (!tld->source_node->data.fn_proto.is_extern && + tld->source_node->data.fn_proto.is_var_args) + { + add_node_error(g, tld->source_node, buf_sprintf("non-extern function is variadic")); + return; + } } else if (tld->id == TldIdUsingNamespace) { g->resolve_queue.append(tld); } diff --git a/src/ir.cpp b/src/ir.cpp @@ -25375,7 +25375,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI case ZigTypeIdBoundFn: case ZigTypeIdStruct: ir_add_error(ira, source_instr, buf_sprintf( - "@Type not availble for 'TypeInfo.%s'", type_id_name(tagTypeId))); + "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId))); return ira->codegen->invalid_inst_gen->value->type; } zig_unreachable(); @@ -27910,11 +27910,10 @@ static IrInstGen *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstSrcFnPro if (cc == CallingConventionC) { break; - } else if (cc == CallingConventionUnspecified) { - lazy_fn_type->is_generic = true; - return result; } else { - zig_unreachable(); + ir_add_error(ira, &instruction->base.base, + buf_sprintf("var args only allowed in functions with C calling convention")); + return ira->codegen->invalid_inst_gen; } } @@ -30979,10 +30978,10 @@ static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, La if (fn_type_id.cc == CallingConventionC) { fn_type_id.param_count = fn_type_id.next_param_index; break; - } else if (fn_type_id.cc == CallingConventionUnspecified) { - return get_generic_fn_type(ira->codegen, &fn_type_id); } else { - zig_unreachable(); + ir_add_error_node(ira, param_node, + buf_sprintf("var args only allowed in functions with C calling convention")); + return nullptr; } } FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; diff --git a/test/compile_errors.zig b/test/compile_errors.zig @@ -2,6 +2,15 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add("non-extern function with var args", + \\fn foo(args: ...) void {} + \\export fn entry() void { + \\ foo(); + \\} + , &[_][]const u8{ + "tmp.zig:1:1: error: non-extern function is variadic", + }); + cases.addTest("invalid int casts", \\export fn foo() void { \\ var a: u32 = 2; @@ -703,15 +712,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:28: error: invalid character: ';'", }); - cases.add("var args without c calling conv", - \\fn foo(args: ...) void {} - \\comptime { - \\ _ = foo; - \\} - , &[_][]const u8{ - "tmp.zig:1:8: error: var args only allowed in functions with C calling convention", - }); - cases.add("comptime struct field, no init value", \\const Foo = struct { \\ comptime b: i32, @@ -856,7 +856,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:11:25: error: expected type 'u32', found '@TypeOf(get_uval).ReturnType.ErrorSet!u32'", }); - cases.add("asigning to struct or union fields that are not optionals with a function that returns an optional", + cases.add("assigning to struct or union fields that are not optionals with a function that returns an optional", \\fn maybe(is: bool) ?u8 { \\ if (is) return @as(u8, 10) else return null; \\} @@ -1084,7 +1084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @Type(@typeInfo(struct { })); \\} , &[_][]const u8{ - "tmp.zig:2:15: error: @Type not availble for 'TypeInfo.Struct'", + "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'", }); cases.add("wrong type for result ptr to @asyncCall", @@ -2659,7 +2659,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:17: error: switch on type 'type' provides no expression parameter", }); - cases.add("function protoype with no body", + cases.add("function prototype with no body", \\fn foo() void; \\export fn entry() void { \\ foo(); diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig @@ -13,7 +13,7 @@ test "type info: tag type, void info" { fn testBasic() void { expect(@TagType(TypeInfo) == TypeId); const void_info = @typeInfo(void); - expect(@as(TypeId, void_info) == TypeId.Void); + expect(void_info == TypeId.Void); expect(void_info.Void == {}); } @@ -24,12 +24,12 @@ test "type info: integer, floating point type info" { fn testIntFloat() void { const u8_info = @typeInfo(u8); - expect(@as(TypeId, u8_info) == TypeId.Int); + expect(u8_info == .Int); expect(!u8_info.Int.is_signed); expect(u8_info.Int.bits == 8); const f64_info = @typeInfo(f64); - expect(@as(TypeId, f64_info) == TypeId.Float); + expect(f64_info == .Float); expect(f64_info.Float.bits == 64); } @@ -40,7 +40,7 @@ test "type info: pointer type info" { fn testPointer() void { const u32_ptr_info = @typeInfo(*u32); - expect(@as(TypeId, u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info == .Pointer); expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); expect(u32_ptr_info.Pointer.is_const == false); expect(u32_ptr_info.Pointer.is_volatile == false); @@ -56,7 +56,7 @@ test "type info: unknown length pointer type info" { fn testUnknownLenPtr() void { const u32_ptr_info = @typeInfo([*]const volatile f64); - expect(@as(TypeId, u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info == .Pointer); expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); expect(u32_ptr_info.Pointer.is_const == true); expect(u32_ptr_info.Pointer.is_volatile == true); @@ -72,7 +72,7 @@ test "type info: null terminated pointer type info" { fn testNullTerminatedPtr() void { const ptr_info = @typeInfo([*:0]u8); - expect(@as(TypeId, ptr_info) == TypeId.Pointer); + expect(ptr_info == .Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); expect(ptr_info.Pointer.is_const == false); expect(ptr_info.Pointer.is_volatile == false); @@ -91,8 +91,8 @@ test "type info: C pointer type info" { fn testCPtr() void { const ptr_info = @typeInfo([*c]align(4) const i8); - expect(@as(TypeId, ptr_info) == TypeId.Pointer); - expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); + expect(ptr_info == .Pointer); + expect(ptr_info.Pointer.size == .C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); expect(ptr_info.Pointer.alignment == 4); @@ -106,8 +106,8 @@ test "type info: slice type info" { fn testSlice() void { const u32_slice_info = @typeInfo([]u32); - expect(@as(TypeId, u32_slice_info) == TypeId.Pointer); - expect(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); + expect(u32_slice_info == .Pointer); + expect(u32_slice_info.Pointer.size == .Slice); expect(u32_slice_info.Pointer.is_const == false); expect(u32_slice_info.Pointer.is_volatile == false); expect(u32_slice_info.Pointer.alignment == 4); @@ -121,7 +121,7 @@ test "type info: array type info" { fn testArray() void { const arr_info = @typeInfo([42]bool); - expect(@as(TypeId, arr_info) == TypeId.Array); + expect(arr_info == .Array); expect(arr_info.Array.len == 42); expect(arr_info.Array.child == bool); } @@ -133,7 +133,7 @@ test "type info: optional type info" { fn testOptional() void { const null_info = @typeInfo(?void); - expect(@as(TypeId, null_info) == TypeId.Optional); + expect(null_info == .Optional); expect(null_info.Optional.child == void); } @@ -150,18 +150,18 @@ fn testErrorSet() void { }; const error_set_info = @typeInfo(TestErrorSet); - expect(@as(TypeId, error_set_info) == TypeId.ErrorSet); + expect(error_set_info == .ErrorSet); expect(error_set_info.ErrorSet.?.len == 3); expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First")); expect(error_set_info.ErrorSet.?[2].value == @errorToInt(TestErrorSet.Third)); const error_union_info = @typeInfo(TestErrorSet!usize); - expect(@as(TypeId, error_union_info) == TypeId.ErrorUnion); + expect(error_union_info == .ErrorUnion); expect(error_union_info.ErrorUnion.error_set == TestErrorSet); expect(error_union_info.ErrorUnion.payload == usize); const global_info = @typeInfo(anyerror); - expect(@as(TypeId, global_info) == TypeId.ErrorSet); + expect(global_info == .ErrorSet); expect(global_info.ErrorSet == null); } @@ -179,8 +179,8 @@ fn testEnum() void { }; const os_info = @typeInfo(Os); - expect(@as(TypeId, os_info) == TypeId.Enum); - expect(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + expect(os_info == .Enum); + expect(os_info.Enum.layout == .Auto); expect(os_info.Enum.fields.len == 4); expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); expect(os_info.Enum.fields[3].value == 3); @@ -195,8 +195,8 @@ test "type info: union info" { fn testUnion() void { const typeinfo_info = @typeInfo(TypeInfo); - expect(@as(TypeId, typeinfo_info) == TypeId.Union); - expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); + expect(typeinfo_info == .Union); + expect(typeinfo_info.Union.layout == .Auto); expect(typeinfo_info.Union.tag_type.? == TypeId); expect(typeinfo_info.Union.fields.len == 25); expect(typeinfo_info.Union.fields[4].enum_field != null); @@ -210,9 +210,9 @@ fn testUnion() void { }; const notag_union_info = @typeInfo(TestNoTagUnion); - expect(@as(TypeId, notag_union_info) == TypeId.Union); + expect(notag_union_info == .Union); expect(notag_union_info.Union.tag_type == null); - expect(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + expect(notag_union_info.Union.layout == .Auto); expect(notag_union_info.Union.fields.len == 2); expect(notag_union_info.Union.fields[0].enum_field == null); expect(notag_union_info.Union.fields[1].field_type == u32); @@ -222,7 +222,7 @@ fn testUnion() void { }; const extern_union_info = @typeInfo(TestExternUnion); - expect(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + expect(extern_union_info.Union.layout == .Extern); expect(extern_union_info.Union.tag_type == null); expect(extern_union_info.Union.fields[0].enum_field == null); expect(extern_union_info.Union.fields[0].field_type == *c_void); @@ -235,8 +235,8 @@ test "type info: struct info" { fn testStruct() void { const struct_info = @typeInfo(TestStruct); - expect(@as(TypeId, struct_info) == TypeId.Struct); - expect(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + expect(struct_info == .Struct); + expect(struct_info.Struct.layout == .Packed); expect(struct_info.Struct.fields.len == 4); expect(struct_info.Struct.fields[1].offset == null); expect(struct_info.Struct.fields[2].field_type == *TestStruct); @@ -268,22 +268,20 @@ test "type info: function type info" { fn testFunction() void { const fn_info = @typeInfo(@TypeOf(foo)); - expect(@as(TypeId, fn_info) == TypeId.Fn); - expect(fn_info.Fn.calling_convention == .Unspecified); - expect(fn_info.Fn.is_generic); + expect(fn_info == .Fn); + expect(fn_info.Fn.calling_convention == .C); + expect(!fn_info.Fn.is_generic); expect(fn_info.Fn.args.len == 2); expect(fn_info.Fn.is_var_args); - expect(fn_info.Fn.return_type == null); + expect(fn_info.Fn.return_type.? == usize); const test_instance: TestStruct = undefined; const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo)); - expect(@as(TypeId, bound_fn_info) == TypeId.BoundFn); + expect(bound_fn_info == .BoundFn); expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); } -fn foo(comptime a: usize, b: bool, args: ...) usize { - return 0; -} +extern fn foo(a: usize, b: bool, args: ...) usize; test "typeInfo with comptime parameter in struct fn def" { const S = struct { @@ -299,7 +297,7 @@ test "type info: vectors" { fn testVector() void { const vec_info = @typeInfo(@Vector(4, i32)); - expect(@as(TypeId, vec_info) == TypeId.Vector); + expect(vec_info == .Vector); expect(vec_info.Vector.len == 4); expect(vec_info.Vector.child == i32); } @@ -312,13 +310,13 @@ test "type info: anyframe and anyframe->T" { fn testAnyFrame() void { { const anyframe_info = @typeInfo(anyframe->i32); - expect(@as(TypeId, anyframe_info) == .AnyFrame); + expect(anyframe_info == .AnyFrame); expect(anyframe_info.AnyFrame.child.? == i32); } { const anyframe_info = @typeInfo(anyframe); - expect(@as(TypeId, anyframe_info) == .AnyFrame); + expect(anyframe_info == .AnyFrame); expect(anyframe_info.AnyFrame.child == null); } }