Merge pull request #5088 from Vexu/varargs-fix

Add error for non-exter variadic functions
This commit is contained in:
Andrew Kelley 2020-04-18 14:35:35 -04:00 committed by GitHub
commit 6b2274fd99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 56 deletions

View File

@ -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);
}

View File

@ -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];

View File

@ -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();

View File

@ -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);
}
}