authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-23 16:40:17-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-23 16:40:17-05:00
log17cb85dfb837949cd3a559fe8e99dee1f72463a4
treea35d23e26938586ba0fb706964e2b7c2b4b894f7
parent1826a961608037405237f12df5aec94f8f5f3a10

basic support for functions with variable length arguments

See #77

11 files changed, 257 insertions(+), 63 deletions(-)

doc/langref.md+1-1
...@@ -33,7 +33,7 @@ FnDef = option("inline" | "extern") FnProto Block...@@ -33,7 +33,7 @@ FnDef = option("inline" | "extern") FnProto Block
3333
34ParamDeclList = "(" list(ParamDecl, ",") ")"34ParamDeclList = "(" list(ParamDecl, ",") ")"
3535
36ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..."36ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
3737
38Block = "{" list(option(Statement), ";") "}"38Block = "{" list(option(Statement), ";") "}"
3939
src/all_types.hpp+11
...@@ -122,6 +122,11 @@ struct ConstBoundFnValue {...@@ -122,6 +122,11 @@ struct ConstBoundFnValue {
122 IrInstruction *first_arg;122 IrInstruction *first_arg;
123};123};
124124
125struct ConstArgTuple {
126 size_t start_index;
127 size_t end_index;
128};
129
125enum ConstValSpecial {130enum ConstValSpecial {
126 ConstValSpecialRuntime,131 ConstValSpecialRuntime,
127 ConstValSpecialStatic,132 ConstValSpecialStatic,
...@@ -163,6 +168,7 @@ struct ConstExprValue {...@@ -163,6 +168,7 @@ struct ConstExprValue {
163 ConstPtrValue x_ptr;168 ConstPtrValue x_ptr;
164 ImportTableEntry *x_import;169 ImportTableEntry *x_import;
165 Scope *x_block;170 Scope *x_block;
171 ConstArgTuple x_arg_tuple;
166172
167 // populated if special == ConstValSpecialRuntime173 // populated if special == ConstValSpecialRuntime
168 RuntimeHintErrorUnion rh_error_union;174 RuntimeHintErrorUnion rh_error_union;
...@@ -325,6 +331,7 @@ struct AstNodeParamDecl {...@@ -325,6 +331,7 @@ struct AstNodeParamDecl {
325 AstNode *type;331 AstNode *type;
326 bool is_noalias;332 bool is_noalias;
327 bool is_inline;333 bool is_inline;
334 bool is_var_args;
328};335};
329336
330struct AstNodeBlock {337struct AstNodeBlock {
...@@ -936,6 +943,7 @@ enum TypeTableEntryId {...@@ -936,6 +943,7 @@ enum TypeTableEntryId {
936 TypeTableEntryIdNamespace,943 TypeTableEntryIdNamespace,
937 TypeTableEntryIdBlock,944 TypeTableEntryIdBlock,
938 TypeTableEntryIdBoundFn,945 TypeTableEntryIdBoundFn,
946 TypeTableEntryIdArgTuple,
939};947};
940948
941struct TypeTableEntry {949struct TypeTableEntry {
...@@ -1034,6 +1042,8 @@ struct FnTableEntry {...@@ -1034,6 +1042,8 @@ struct FnTableEntry {
10341042
1035 ZigList<IrInstruction *> alloca_list;1043 ZigList<IrInstruction *> alloca_list;
1036 ZigList<VariableTableEntry *> variable_list;1044 ZigList<VariableTableEntry *> variable_list;
1045
1046 VariableTableEntry *var_args_var;
1037};1047};
10381048
1039uint32_t fn_table_entry_hash(FnTableEntry*);1049uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -1155,6 +1165,7 @@ struct CodeGen {...@@ -1155,6 +1165,7 @@ struct CodeGen {
1155 TypeTableEntry *entry_environ_enum;1165 TypeTableEntry *entry_environ_enum;
1156 TypeTableEntry *entry_oformat_enum;1166 TypeTableEntry *entry_oformat_enum;
1157 TypeTableEntry *entry_atomic_order_enum;1167 TypeTableEntry *entry_atomic_order_enum;
1168 TypeTableEntry *entry_arg_tuple;
1158 } builtin_types;1169 } builtin_types;
11591170
1160 ZigTarget zig_target;1171 ZigTarget zig_target;
src/analyze.cpp+52-10
...@@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {...@@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
208 case TypeTableEntryIdBlock:208 case TypeTableEntryIdBlock:
209 case TypeTableEntryIdBoundFn:209 case TypeTableEntryIdBoundFn:
210 case TypeTableEntryIdEnumTag:210 case TypeTableEntryIdEnumTag:
211 case TypeTableEntryIdArgTuple:
211 return true;212 return true;
212 }213 }
213 zig_unreachable();214 zig_unreachable();
...@@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {...@@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
245 case TypeTableEntryIdBlock:246 case TypeTableEntryIdBlock:
246 case TypeTableEntryIdBoundFn:247 case TypeTableEntryIdBoundFn:
247 case TypeTableEntryIdEnumTag:248 case TypeTableEntryIdEnumTag:
249 case TypeTableEntryIdArgTuple:
248 return true;250 return true;
249 }251 }
250 zig_unreachable();252 zig_unreachable();
...@@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
921 assert(param_node->type == NodeTypeParamDecl);923 assert(param_node->type == NodeTypeParamDecl);
922924
923 bool param_is_inline = param_node->data.param_decl.is_inline;925 bool param_is_inline = param_node->data.param_decl.is_inline;
926 bool param_is_var_args = param_node->data.param_decl.is_var_args;
924927
925 if (param_is_inline) {928 if (param_is_inline) {
926 if (fn_type_id.is_extern) {929 if (fn_type_id.is_extern) {
...@@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
929 return g->builtin_types.entry_invalid;932 return g->builtin_types.entry_invalid;
930 }933 }
931 return get_generic_fn_type(g, &fn_type_id);934 return get_generic_fn_type(g, &fn_type_id);
935 } else if (param_is_var_args) {
936 if (fn_type_id.is_extern) {
937 fn_type_id.param_count = fn_type_id.next_param_index;
938 continue;
939 } else {
940 return get_generic_fn_type(g, &fn_type_id);
941 }
932 }942 }
933943
934 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);944 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
...@@ -939,6 +949,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -939,6 +949,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
939 case TypeTableEntryIdUnreachable:949 case TypeTableEntryIdUnreachable:
940 case TypeTableEntryIdUndefLit:950 case TypeTableEntryIdUndefLit:
941 case TypeTableEntryIdNullLit:951 case TypeTableEntryIdNullLit:
952 case TypeTableEntryIdArgTuple:
942 add_node_error(g, param_node->data.param_decl.type,953 add_node_error(g, param_node->data.param_decl.type,
943 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));954 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
944 return g->builtin_types.entry_invalid;955 return g->builtin_types.entry_invalid;
...@@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
9891000
990 case TypeTableEntryIdUndefLit:1001 case TypeTableEntryIdUndefLit:
991 case TypeTableEntryIdNullLit:1002 case TypeTableEntryIdNullLit:
1003 case TypeTableEntryIdArgTuple:
992 add_node_error(g, fn_proto->return_type,1004 add_node_error(g, fn_proto->return_type,
993 buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));1005 buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
994 return g->builtin_types.entry_invalid;1006 return g->builtin_types.entry_invalid;
...@@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
15581570
1559 AstNode *fn_def_node = fn_proto->fn_def_node;1571 AstNode *fn_def_node = fn_proto->fn_def_node;
15601572
1561 if (fn_def_node && fn_proto->is_var_args) {
1562 add_node_error(g, proto_node,
1563 buf_sprintf("variadic arguments only allowed in extern function declarations"));
1564 tld_fn->base.resolution = TldResolutionInvalid;
1565 return;
1566 }
1567
1568 FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node);1573 FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node);
1569 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');1574 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
15701575
...@@ -1799,6 +1804,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt...@@ -1799,6 +1804,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
1799 case TypeTableEntryIdUndefLit:1804 case TypeTableEntryIdUndefLit:
1800 case TypeTableEntryIdNullLit:1805 case TypeTableEntryIdNullLit:
1801 case TypeTableEntryIdBlock:1806 case TypeTableEntryIdBlock:
1807 case TypeTableEntryIdArgTuple:
1802 add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",1808 add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
1803 buf_ptr(&underlying_type->name)));1809 buf_ptr(&underlying_type->name)));
1804 return g->builtin_types.entry_invalid;1810 return g->builtin_types.entry_invalid;
...@@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) {...@@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) {
2210 case TypeTableEntryIdBlock:2216 case TypeTableEntryIdBlock:
2211 case TypeTableEntryIdBoundFn:2217 case TypeTableEntryIdBoundFn:
2212 case TypeTableEntryIdEnumTag:2218 case TypeTableEntryIdEnumTag:
2219 case TypeTableEntryIdArgTuple:
2213 return false;2220 return false;
2214 }2221 }
2215 zig_unreachable();2222 zig_unreachable();
...@@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {...@@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
2260 case TypeTableEntryIdInvalid:2267 case TypeTableEntryIdInvalid:
2261 case TypeTableEntryIdVar:2268 case TypeTableEntryIdVar:
2262 case TypeTableEntryIdEnumTag:2269 case TypeTableEntryIdEnumTag:
2270 case TypeTableEntryIdArgTuple:
2263 zig_unreachable();2271 zig_unreachable();
2264 }2272 }
2265}2273}
...@@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari...@@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
2290 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {2298 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
2291 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];2299 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
2292 AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);2300 AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
2293 Buf *param_name = param_decl_node ? param_decl_node->data.param_decl.name : buf_sprintf("arg%zu", i);2301 Buf *param_name;
2302 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
2303 if (param_decl_node && !is_var_args) {
2304 param_name = param_decl_node->data.param_decl.name;
2305 } else {
2306 param_name = buf_sprintf("arg%zu", i);
2307 }
22942308
2295 TypeTableEntry *param_type = param_info->type;2309 TypeTableEntry *param_type = param_info->type;
2296 bool is_noalias = param_info->is_noalias;2310 bool is_noalias = param_info->is_noalias;
...@@ -2308,6 +2322,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari...@@ -2308,6 +2322,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
2308 param_name, true, create_const_runtime(param_type));2322 param_name, true, create_const_runtime(param_type));
2309 var->src_arg_index = i;2323 var->src_arg_index = i;
2310 fn_table_entry->child_scope = var->child_scope;2324 fn_table_entry->child_scope = var->child_scope;
2325 var->shadowable = var->shadowable || is_var_args;
23112326
2312 if (type_has_bits(param_type)) {2327 if (type_has_bits(param_type)) {
2313 fn_table_entry->variable_list.append(var);2328 fn_table_entry->variable_list.append(var);
...@@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
2627 case TypeTableEntryIdBlock:2642 case TypeTableEntryIdBlock:
2628 case TypeTableEntryIdBoundFn:2643 case TypeTableEntryIdBoundFn:
2629 case TypeTableEntryIdVar:2644 case TypeTableEntryIdVar:
2645 case TypeTableEntryIdArgTuple:
2630 zig_unreachable();2646 zig_unreachable();
2631 case TypeTableEntryIdUnreachable:2647 case TypeTableEntryIdUnreachable:
2632 case TypeTableEntryIdVoid:2648 case TypeTableEntryIdVoid:
...@@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
2742 case TypeTableEntryIdFloat:2758 case TypeTableEntryIdFloat:
2743 case TypeTableEntryIdNumLitFloat:2759 case TypeTableEntryIdNumLitFloat:
2744 return const_val->data.x_bignum.data.x_float * UINT32_MAX;2760 return const_val->data.x_bignum.data.x_float * UINT32_MAX;
2761 case TypeTableEntryIdArgTuple:
2762 return const_val->data.x_arg_tuple.start_index * 281907309 +
2763 const_val->data.x_arg_tuple.end_index * 2290442768;
2745 case TypeTableEntryIdPointer:2764 case TypeTableEntryIdPointer:
2746 return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index);2765 return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index);
2747 case TypeTableEntryIdUndefLit:2766 case TypeTableEntryIdUndefLit:
...@@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {...@@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {
2805bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {2824bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
2806 assert(a->fn_entry);2825 assert(a->fn_entry);
2807 if (a->fn_entry != b->fn_entry) return false;2826 if (a->fn_entry != b->fn_entry) return false;
2808 assert(a->param_count == b->param_count);2827 if (a->param_count != b->param_count) return false;
2809 for (size_t i = 0; i < a->param_count; i += 1) {2828 for (size_t i = 0; i < a->param_count; i += 1) {
2810 ConstExprValue *a_val = &a->params[i];2829 ConstExprValue *a_val = &a->params[i];
2811 ConstExprValue *b_val = &b->params[i];2830 ConstExprValue *b_val = &b->params[i];
...@@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)...@@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
2904 case TypeTableEntryIdBlock:2923 case TypeTableEntryIdBlock:
2905 case TypeTableEntryIdBoundFn:2924 case TypeTableEntryIdBoundFn:
2906 case TypeTableEntryIdVar:2925 case TypeTableEntryIdVar:
2926 case TypeTableEntryIdArgTuple:
2907 zig_unreachable();2927 zig_unreachable();
2908 case TypeTableEntryIdArray:2928 case TypeTableEntryIdArray:
2909 return type_of_first_thing_in_memory(type_entry->data.array.child_type);2929 return type_of_first_thing_in_memory(type_entry->data.array.child_type);
...@@ -2946,6 +2966,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {...@@ -2946,6 +2966,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
2946 case TypeTableEntryIdNamespace:2966 case TypeTableEntryIdNamespace:
2947 case TypeTableEntryIdBlock:2967 case TypeTableEntryIdBlock:
2948 case TypeTableEntryIdBoundFn:2968 case TypeTableEntryIdBoundFn:
2969 case TypeTableEntryIdArgTuple:
2949 return true;2970 return true;
2950 case TypeTableEntryIdArray:2971 case TypeTableEntryIdArray:
2951 case TypeTableEntryIdStruct:2972 case TypeTableEntryIdStruct:
...@@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in...@@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in
3155 return const_val;3176 return const_val;
3156}3177}
31573178
3179void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end) {
3180 const_val->special = ConstValSpecialStatic;
3181 const_val->type = g->builtin_types.entry_arg_tuple;
3182 const_val->data.x_arg_tuple.start_index = arg_index_start;
3183 const_val->data.x_arg_tuple.end_index = arg_index_end;
3184}
3185
3186ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end) {
3187 ConstExprValue *const_val = allocate<ConstExprValue>(1);
3188 init_const_arg_tuple(g, const_val, arg_index_start, arg_index_end);
3189 return const_val;
3190}
3191
3192
3158void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) {3193void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) {
3159 if (type_entry->id == TypeTableEntryIdStruct) {3194 if (type_entry->id == TypeTableEntryIdStruct) {
3160 if (!type_entry->data.structure.complete)3195 if (!type_entry->data.structure.complete)
...@@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {...@@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
3245 return a->data.x_import == b->data.x_import;3280 return a->data.x_import == b->data.x_import;
3246 case TypeTableEntryIdBlock:3281 case TypeTableEntryIdBlock:
3247 return a->data.x_block == b->data.x_block;3282 return a->data.x_block == b->data.x_block;
3283 case TypeTableEntryIdArgTuple:
3284 return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
3285 a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;
3248 case TypeTableEntryIdBoundFn:3286 case TypeTableEntryIdBoundFn:
3249 case TypeTableEntryIdInvalid:3287 case TypeTableEntryIdInvalid:
3250 case TypeTableEntryIdUnreachable:3288 case TypeTableEntryIdUnreachable:
...@@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {...@@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
3506 buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));3544 buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
3507 return;3545 return;
3508 }3546 }
3547 case TypeTableEntryIdArgTuple:
3548 {
3549 buf_appendf(buf, "(args value)");
3550 return;
3551 }
3509 }3552 }
3510 zig_unreachable();3553 zig_unreachable();
3511}3554}
3512
src/analyze.hpp+3
...@@ -133,4 +133,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr...@@ -133,4 +133,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
133 size_t start, size_t len, bool is_const);133 size_t start, size_t len, bool is_const);
134ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);134ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);
135135
136void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end);
137ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end);
138
136#endif139#endif
src/ast_render.cpp+6-6
...@@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
393 print_symbol(ar, node->data.fn_proto.name);393 print_symbol(ar, node->data.fn_proto.name);
394 fprintf(ar->f, "(");394 fprintf(ar->f, "(");
395 int arg_count = node->data.fn_proto.params.length;395 int arg_count = node->data.fn_proto.params.length;
396 bool is_var_args = node->data.fn_proto.is_var_args;
397 for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {396 for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
398 AstNode *param_decl = node->data.fn_proto.params.at(arg_i);397 AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
399 assert(param_decl->type == NodeTypeParamDecl);398 assert(param_decl->type == NodeTypeParamDecl);
...@@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
404 print_symbol(ar, param_decl->data.param_decl.name);403 print_symbol(ar, param_decl->data.param_decl.name);
405 fprintf(ar->f, ": ");404 fprintf(ar->f, ": ");
406 }405 }
407 render_node_grouped(ar, param_decl->data.param_decl.type);406 if (param_decl->data.param_decl.is_var_args) {
407 fprintf(ar->f, "...");
408 } else {
409 render_node_grouped(ar, param_decl->data.param_decl.type);
410 }
408411
409 if (arg_i + 1 < arg_count || is_var_args) {412 if (arg_i + 1 < arg_count) {
410 fprintf(ar->f, ", ");413 fprintf(ar->f, ", ");
411 }414 }
412 }415 }
413 if (is_var_args) {
414 fprintf(ar->f, "...");
415 }
416 fprintf(ar->f, ")");416 fprintf(ar->f, ")");
417417
418 AstNode *return_type_node = node->data.fn_proto.return_type;418 AstNode *return_type_node = node->data.fn_proto.return_type;
src/codegen.cpp+8
...@@ -2636,6 +2636,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -2636,6 +2636,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
2636 case TypeTableEntryIdBlock:2636 case TypeTableEntryIdBlock:
2637 case TypeTableEntryIdBoundFn:2637 case TypeTableEntryIdBoundFn:
2638 case TypeTableEntryIdVar:2638 case TypeTableEntryIdVar:
2639 case TypeTableEntryIdArgTuple:
2639 zig_unreachable();2640 zig_unreachable();
26402641
2641 }2642 }
...@@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) {...@@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) {
3179 buf_init_from_str(&entry->name, "(var)");3180 buf_init_from_str(&entry->name, "(var)");
3180 g->builtin_types.entry_var = entry;3181 g->builtin_types.entry_var = entry;
3181 }3182 }
3183 {
3184 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArgTuple);
3185 buf_init_from_str(&entry->name, "(args)");
3186 entry->zero_bits = true;
3187 g->builtin_types.entry_arg_tuple = entry;
3188 }
31823189
3183 for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {3190 for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
3184 size_t size_in_bits = int_sizes_in_bits[int_size_i];3191 size_t size_in_bits = int_sizes_in_bits[int_size_i];
...@@ -3947,6 +3954,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {...@@ -3947,6 +3954,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
3947 case TypeTableEntryIdUndefLit:3954 case TypeTableEntryIdUndefLit:
3948 case TypeTableEntryIdNullLit:3955 case TypeTableEntryIdNullLit:
3949 case TypeTableEntryIdVar:3956 case TypeTableEntryIdVar:
3957 case TypeTableEntryIdArgTuple:
3950 zig_unreachable();3958 zig_unreachable();
3951 }3959 }
3952}3960}
src/ir.cpp+120-29
...@@ -4347,8 +4347,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -4347,8 +4347,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
43474347
4348 IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);4348 IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
43494349
4350 IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val);4350 IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
4351 IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type);
4352 IrInstruction *elem_var_type;4351 IrInstruction *elem_var_type;
4353 if (node->data.for_expr.elem_is_ptr) {4352 if (node->data.for_expr.elem_is_ptr) {
4354 elem_var_type = pointer_type;4353 elem_var_type = pointer_type;
...@@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
6887 case TypeTableEntryIdNamespace:6886 case TypeTableEntryIdNamespace:
6888 case TypeTableEntryIdBlock:6887 case TypeTableEntryIdBlock:
6889 case TypeTableEntryIdBoundFn:6888 case TypeTableEntryIdBoundFn:
6889 case TypeTableEntryIdArgTuple:
6890 if (!is_equality_cmp) {6890 if (!is_equality_cmp) {
6891 ir_add_error_node(ira, source_node,6891 ir_add_error_node(ira, source_node,
6892 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));6892 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
...@@ -7449,6 +7449,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -7449,6 +7449,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
7449 case TypeTableEntryIdFn:7449 case TypeTableEntryIdFn:
7450 case TypeTableEntryIdBoundFn:7450 case TypeTableEntryIdBoundFn:
7451 case TypeTableEntryIdEnumTag:7451 case TypeTableEntryIdEnumTag:
7452 case TypeTableEntryIdArgTuple:
7452 // OK7453 // OK
7453 break;7454 break;
7454 }7455 }
...@@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
7520{7521{
7521 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i);7522 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i);
7522 assert(param_decl_node->type == NodeTypeParamDecl);7523 assert(param_decl_node->type == NodeTypeParamDecl);
7523 AstNode *param_type_node = param_decl_node->data.param_decl.type;7524 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
7524 TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);7525 bool arg_part_of_generic_id = false;
7525 if (param_type->id == TypeTableEntryIdInvalid)7526 IrInstruction *casted_arg;
7526 return false;7527 if (is_var_args) {
7528 arg_part_of_generic_id = true;
7529 casted_arg = arg;
7530 } else {
7531 AstNode *param_type_node = param_decl_node->data.param_decl.type;
7532 TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);
7533 if (param_type->id == TypeTableEntryIdInvalid)
7534 return false;
75277535
7528 IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type);7536 bool is_var_type = (param_type->id == TypeTableEntryIdVar);
7529 if (casted_arg->value.type->id == TypeTableEntryIdInvalid)7537 if (is_var_type) {
7530 return false;7538 arg_part_of_generic_id = true;
7539 casted_arg = arg;
7540 } else {
7541 casted_arg = ir_implicit_cast(ira, arg, param_type);
7542 if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
7543 return false;
7544 }
7545 }
75317546
7532 bool inline_arg = param_decl_node->data.param_decl.is_inline;7547 bool comptime_arg = param_decl_node->data.param_decl.is_inline;
7533 bool is_var_type = (param_type->id == TypeTableEntryIdVar);
75347548
7535 ConstExprValue *arg_val;7549 ConstExprValue *arg_val;
75367550
7537 if (inline_arg) {7551 if (comptime_arg) {
7552 arg_part_of_generic_id = true;
7538 arg_val = ir_resolve_const(ira, casted_arg, UndefBad);7553 arg_val = ir_resolve_const(ira, casted_arg, UndefBad);
7539 if (!arg_val)7554 if (!arg_val)
7540 return false;7555 return false;
...@@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
7544 } else {7559 } else {
7545 arg_val = create_const_runtime(casted_arg->value.type);7560 arg_val = create_const_runtime(casted_arg->value.type);
7546 }7561 }
7562 if (arg_part_of_generic_id) {
7563 generic_id->params[generic_id->param_count] = *arg_val;
7564 generic_id->param_count += 1;
7565 }
75477566
7548 Buf *param_name = param_decl_node->data.param_decl.name;7567 Buf *param_name = param_decl_node->data.param_decl.name;
7549 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,7568 if (is_var_args) {
7550 *child_scope, param_name, true, arg_val);7569 if (!impl_fn->var_args_var) {
7551 var->value.depends_on_compile_var = true;7570 ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
7552 *child_scope = var->child_scope;7571 fn_type_id->param_count, fn_type_id->param_count + 1);
7572 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
7573 *child_scope, param_name, true, var_args_val);
7574 var->value.depends_on_compile_var = true;
7575 *child_scope = var->child_scope;
7576 impl_fn->var_args_var = var;
7577 }
7578 impl_fn->var_args_var->value.data.x_arg_tuple.end_index = fn_type_id->param_count + 1;
75537579
7554 if (inline_arg || is_var_type) {7580 } else {
7555 generic_id->params[generic_id->param_count] = *arg_val;7581 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
7556 generic_id->param_count += 1;7582 *child_scope, param_name, true, arg_val);
7583 var->value.depends_on_compile_var = true;
7584 *child_scope = var->child_scope;
7585 var->shadowable = !comptime_arg;
7586
7587 *next_proto_i += 1;
7557 }7588 }
7558 if (!inline_arg) {7589
7559 if (type_requires_comptime(var->value.type)) {7590 if (!comptime_arg) {
7560 ir_add_error(ira, arg,7591 if (type_requires_comptime(casted_arg->value.type)) {
7561 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->value.type->name)));7592 ir_add_error(ira, casted_arg,
7593 buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name)));
7562 return false;7594 return false;
7563 }7595 }
75647596
7565 var->shadowable = true;
7566
7567 casted_args[fn_type_id->param_count] = casted_arg;7597 casted_args[fn_type_id->param_count] = casted_arg;
7568 FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count];7598 FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count];
7569 param_info->type = casted_arg->value.type;7599 param_info->type = casted_arg->value.type;
...@@ -7571,7 +7601,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -7571,7 +7601,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
7571 impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node;7601 impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node;
7572 fn_type_id->param_count += 1;7602 fn_type_id->param_count += 1;
7573 }7603 }
7574 *next_proto_i += 1;7604
7575 return true;7605 return true;
7576}7606}
75777607
...@@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
7682 FnTypeId inst_fn_type_id = {0};7712 FnTypeId inst_fn_type_id = {0};
7683 init_fn_type_id(&inst_fn_type_id, fn_proto_node);7713 init_fn_type_id(&inst_fn_type_id, fn_proto_node);
7684 inst_fn_type_id.param_count = 0;7714 inst_fn_type_id.param_count = 0;
7715 inst_fn_type_id.is_var_args = false;
76857716
7686 // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly7717 // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly
7687 // as the key in generic_table7718 // as the key in generic_table
...@@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct...@@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
7918 case TypeTableEntryIdBlock:7949 case TypeTableEntryIdBlock:
7919 case TypeTableEntryIdUnreachable:7950 case TypeTableEntryIdUnreachable:
7920 case TypeTableEntryIdVar:7951 case TypeTableEntryIdVar:
7952 case TypeTableEntryIdArgTuple:
7921 ir_add_error_node(ira, un_op_instruction->base.source_node,7953 ir_add_error_node(ira, un_op_instruction->base.source_node,
7922 buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));7954 buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
7923 // TODO if meta_type is type decl, add note pointing to type decl declaration7955 // TODO if meta_type is type decl, add note pointing to type decl declaration
...@@ -7990,6 +8022,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op...@@ -7990,6 +8022,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
7990 case TypeTableEntryIdBlock:8022 case TypeTableEntryIdBlock:
7991 case TypeTableEntryIdBoundFn:8023 case TypeTableEntryIdBoundFn:
7992 case TypeTableEntryIdEnumTag:8024 case TypeTableEntryIdEnumTag:
8025 case TypeTableEntryIdArgTuple:
7993 {8026 {
7994 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,8027 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
7995 value->value.depends_on_compile_var);8028 value->value.depends_on_compile_var);
...@@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
8327 return_type = array_type;8360 return_type = array_type;
8328 } else if (is_slice(array_type)) {8361 } else if (is_slice(array_type)) {
8329 return_type = array_type->data.structure.fields[0].type_entry;8362 return_type = array_type->data.structure.fields[0].type_entry;
8363 } else if (array_type->id == TypeTableEntryIdArgTuple) {
8364 ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
8365 if (!ptr_val)
8366 return ira->codegen->builtin_types.entry_invalid;
8367 ConstExprValue *args_val = const_ptr_pointee(ptr_val);
8368 size_t start = args_val->data.x_arg_tuple.start_index;
8369 size_t end = args_val->data.x_arg_tuple.end_index;
8370 ConstExprValue *elem_index_val = ir_resolve_const(ira, elem_index, UndefBad);
8371 if (!elem_index_val)
8372 return ira->codegen->builtin_types.entry_invalid;
8373 size_t index = bignum_to_twos_complement(&elem_index_val->data.x_bignum);
8374 size_t len = end - start;
8375 if (index >= len) {
8376 ir_add_error(ira, &elem_ptr_instruction->base,
8377 buf_sprintf("index %zu outside argument list of size %zu", index, len));
8378 return ira->codegen->builtin_types.entry_invalid;
8379 }
8380 size_t abs_index = start + index;
8381 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
8382 assert(fn_entry);
8383 VariableTableEntry *var = fn_entry->variable_list.at(abs_index);
8384 bool depends_on_compile_var = array_ptr->value.depends_on_compile_var ||
8385 elem_index->value.depends_on_compile_var;
8386 return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var, true, depends_on_compile_var);
8330 } else {8387 } else {
8331 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,8388 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
8332 buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));8389 buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
...@@ -8572,6 +8629,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru...@@ -8572,6 +8629,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
8572 ConstExprValue *len_val = allocate<ConstExprValue>(1);8629 ConstExprValue *len_val = allocate<ConstExprValue>(1);
8573 init_const_usize(ira->codegen, len_val, container_type->data.array.len);8630 init_const_usize(ira->codegen, len_val, container_type->data.array.len);
85748631
8632 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
8633 bool ptr_is_const = true;
8634 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
8635 usize, false, ConstPtrSpecialNone, ptr_is_const);
8636 } else {
8637 ir_add_error_node(ira, source_node,
8638 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
8639 buf_ptr(&container_type->name)));
8640 return ira->codegen->builtin_types.entry_invalid;
8641 }
8642 } else if (container_type->id == TypeTableEntryIdArgTuple) {
8643 ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
8644 if (!container_ptr_val)
8645 return ira->codegen->builtin_types.entry_invalid;
8646
8647 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
8648 ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
8649
8650 if (buf_eql_str(field_name, "len")) {
8651 ConstExprValue *len_val = allocate<ConstExprValue>(1);
8652 size_t len = child_val->data.x_arg_tuple.end_index - child_val->data.x_arg_tuple.start_index;
8653 init_const_usize(ira->codegen, len_val, len);
8654
8575 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;8655 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
8576 bool ptr_is_const = true;8656 bool ptr_is_const = true;
8577 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,8657 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
...@@ -8830,6 +8910,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi...@@ -8830,6 +8910,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
8830 case TypeTableEntryIdFn:8910 case TypeTableEntryIdFn:
8831 case TypeTableEntryIdTypeDecl:8911 case TypeTableEntryIdTypeDecl:
8832 case TypeTableEntryIdEnumTag:8912 case TypeTableEntryIdEnumTag:
8913 case TypeTableEntryIdArgTuple:
8833 {8914 {
8834 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);8915 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
8835 // TODO depends_on_compile_var should be set based on whether the type of the expression8916 // TODO depends_on_compile_var should be set based on whether the type of the expression
...@@ -8847,8 +8928,8 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi...@@ -8847,8 +8928,8 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
8847static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,8928static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
8848 IrInstructionToPtrType *to_ptr_type_instruction)8929 IrInstructionToPtrType *to_ptr_type_instruction)
8849{8930{
8850 IrInstruction *type_value = to_ptr_type_instruction->value->other;8931 IrInstruction *value = to_ptr_type_instruction->value->other;
8851 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);8932 TypeTableEntry *type_entry = value->value.type;
8852 if (type_entry->id == TypeTableEntryIdInvalid)8933 if (type_entry->id == TypeTableEntryIdInvalid)
8853 return type_entry;8934 return type_entry;
88548935
...@@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,...@@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
8857 ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false);8938 ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false);
8858 } else if (is_slice(type_entry)) {8939 } else if (is_slice(type_entry)) {
8859 ptr_type = type_entry->data.structure.fields[0].type_entry;8940 ptr_type = type_entry->data.structure.fields[0].type_entry;
8941 } else if (type_entry->id == TypeTableEntryIdArgTuple) {
8942 ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad);
8943 if (!arg_tuple_val)
8944 return ira->codegen->builtin_types.entry_invalid;
8945 zig_panic("TODO for loop on var args");
8860 } else {8946 } else {
8861 ir_add_error_node(ira, to_ptr_type_instruction->base.source_node,8947 ir_add_error_node(ira, to_ptr_type_instruction->base.source_node,
8862 buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name)));8948 buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name)));
...@@ -8864,7 +8950,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,...@@ -8864,7 +8950,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
8864 }8950 }
88658951
8866 ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base,8952 ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base,
8867 type_value->value.depends_on_compile_var);8953 value->value.depends_on_compile_var);
8868 out_val->data.x_type = ptr_type;8954 out_val->data.x_type = ptr_type;
8869 return ira->codegen->builtin_types.entry_type;8955 return ira->codegen->builtin_types.entry_type;
8870}8956}
...@@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
9027 case TypeTableEntryIdUndefLit:9113 case TypeTableEntryIdUndefLit:
9028 case TypeTableEntryIdNullLit:9114 case TypeTableEntryIdNullLit:
9029 case TypeTableEntryIdBlock:9115 case TypeTableEntryIdBlock:
9116 case TypeTableEntryIdArgTuple:
9030 ir_add_error_node(ira, slice_type_instruction->base.source_node,9117 ir_add_error_node(ira, slice_type_instruction->base.source_node,
9031 buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));9118 buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));
9032 // TODO if this is a typedecl, add error note showing the declaration of the type decl9119 // TODO if this is a typedecl, add error note showing the declaration of the type decl
...@@ -9118,6 +9205,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -9118,6 +9205,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
9118 case TypeTableEntryIdUndefLit:9205 case TypeTableEntryIdUndefLit:
9119 case TypeTableEntryIdNullLit:9206 case TypeTableEntryIdNullLit:
9120 case TypeTableEntryIdBlock:9207 case TypeTableEntryIdBlock:
9208 case TypeTableEntryIdArgTuple:
9121 ir_add_error_node(ira, array_type_instruction->base.source_node,9209 ir_add_error_node(ira, array_type_instruction->base.source_node,
9122 buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));9210 buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
9123 // TODO if this is a typedecl, add error note showing the declaration of the type decl9211 // TODO if this is a typedecl, add error note showing the declaration of the type decl
...@@ -9214,6 +9302,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -9214,6 +9302,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
9214 case TypeTableEntryIdMetaType:9302 case TypeTableEntryIdMetaType:
9215 case TypeTableEntryIdFn:9303 case TypeTableEntryIdFn:
9216 case TypeTableEntryIdNamespace:9304 case TypeTableEntryIdNamespace:
9305 case TypeTableEntryIdArgTuple:
9217 ir_add_error_node(ira, size_of_instruction->base.source_node,9306 ir_add_error_node(ira, size_of_instruction->base.source_node,
9218 buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));9307 buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
9219 // TODO if this is a typedecl, add error note showing the declaration of the type decl9308 // TODO if this is a typedecl, add error note showing the declaration of the type decl
...@@ -9559,6 +9648,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -9559,6 +9648,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
9559 case TypeTableEntryIdUnion:9648 case TypeTableEntryIdUnion:
9560 case TypeTableEntryIdBlock:9649 case TypeTableEntryIdBlock:
9561 case TypeTableEntryIdBoundFn:9650 case TypeTableEntryIdBoundFn:
9651 case TypeTableEntryIdArgTuple:
9562 ir_add_error(ira, &switch_target_instruction->base,9652 ir_add_error(ira, &switch_target_instruction->base,
9563 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));9653 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
9564 // TODO if this is a typedecl, add error note showing the declaration of the type decl9654 // TODO if this is a typedecl, add error note showing the declaration of the type decl
...@@ -10075,6 +10165,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_...@@ -10075,6 +10165,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
10075 case TypeTableEntryIdNamespace:10165 case TypeTableEntryIdNamespace:
10076 case TypeTableEntryIdBlock:10166 case TypeTableEntryIdBlock:
10077 case TypeTableEntryIdBoundFn:10167 case TypeTableEntryIdBoundFn:
10168 case TypeTableEntryIdArgTuple:
10078 {10169 {
10079 const char *err_format = is_max ?10170 const char *err_format = is_max ?
10080 "no max value available for type '%s'" :10171 "no max value available for type '%s'" :
src/parser.cpp+12-13
...@@ -250,16 +250,11 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool...@@ -250,16 +250,11 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool
250}250}
251251
252/*252/*
253ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..."253ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
254*/254*/
255static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {255static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
256 Token *token = &pc->tokens->at(*token_index);256 Token *token = &pc->tokens->at(*token_index);
257257
258 if (token->id == TokenIdEllipsis) {
259 *token_index += 1;
260 return nullptr;
261 }
262
263 AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token);258 AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token);
264259
265 if (token->id == TokenIdKeywordNoAlias) {260 if (token->id == TokenIdKeywordNoAlias) {
...@@ -282,7 +277,13 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {...@@ -282,7 +277,13 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
282 }277 }
283 }278 }
284279
285 node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);280 Token *ellipsis_tok = &pc->tokens->at(*token_index);
281 if (ellipsis_tok->id == TokenIdEllipsis) {
282 *token_index += 1;
283 node->data.param_decl.is_var_args = true;
284 } else {
285 node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);
286 }
286287
287 return node;288 return node;
288}289}
...@@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index,...@@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index,
304 for (;;) {305 for (;;) {
305 AstNode *param_decl_node = ast_parse_param_decl(pc, token_index);306 AstNode *param_decl_node = ast_parse_param_decl(pc, token_index);
306 bool expect_end = false;307 bool expect_end = false;
307 if (param_decl_node) {308 assert(param_decl_node);
308 params->append(param_decl_node);309 params->append(param_decl_node);
309 } else {310 expect_end = param_decl_node->data.param_decl.is_var_args;
310 *is_var_args = true;311 *is_var_args = expect_end;
311 expect_end = true;
312 }
313312
314 Token *token = &pc->tokens->at(*token_index);313 Token *token = &pc->tokens->at(*token_index);
315 *token_index += 1;314 *token_index += 1;
test/cases/var_args.zig created+16
...@@ -0,0 +1,16 @@
1const assert = @import("std").debug.assert;
2
3fn add(args: ...) -> i32 {
4 var sum = i32(0);
5 {comptime var i: usize = 0; inline while (i < args.len; i += 1) {
6 sum += args[i];
7 }}
8 return sum;
9}
10
11fn testAddArbitraryArgs() {
12 @setFnTest(this);
13
14 assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
15 assert(add(i32(1234)) == 1234);
16}
test/run_tests.cpp+27-4
...@@ -832,10 +832,6 @@ fn f() {...@@ -832,10 +832,6 @@ fn f() {
832 )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'",832 )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'",
833 ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'");833 ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'");
834834
835 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
836fn f(...) {}
837 )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern function declarations");
838
839 add_compile_fail_case("write to const global variable", R"SOURCE(835 add_compile_fail_case("write to const global variable", R"SOURCE(
840const x : i32 = 99;836const x : i32 = 99;
841fn f() {837fn f() {
...@@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 {...@@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 {
1633 return 0;1629 return 0;
1634}1630}
1635 )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression");1631 )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression");
1632
1633 add_compile_fail_case("attempt to access var args out of bounds", R"SOURCE(
1634fn add(args: ...) -> i32 {
1635 args[0] + args[1]
1636}
1637
1638fn foo() -> i32 {
1639 add(i32(1234))
1640}
1641 )SOURCE", 2,
1642 ".tmp_source.zig:3:19: error: index 1 outside argument list of size 1",
1643 ".tmp_source.zig:7:8: note: called from here");
1644
1645 add_compile_fail_case("pass integer literal to var args", R"SOURCE(
1646fn add(args: ...) -> i32 {
1647 var sum = i32(0);
1648 {comptime var i: usize = 0; inline while (i < args.len; i += 1) {
1649 sum += args[i];
1650 }}
1651 return sum;
1652}
1653
1654fn bar() -> i32 {
1655 add(1, 2, 3, 4)
1656}
1657 )SOURCE", 1, ".tmp_source.zig:11:9: error: parameter of type '(integer literal)' requires comptime");
1658
1636}1659}
16371660
1638//////////////////////////////////////////////////////////////////////////////1661//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+1
...@@ -28,4 +28,5 @@ const test_switch = @import("cases/switch.zig");...@@ -28,4 +28,5 @@ const test_switch = @import("cases/switch.zig");
28const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");28const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
29const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");29const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
30const test_this = @import("cases/this.zig");30const test_this = @import("cases/this.zig");
31const test_var_args = @import("cases/var_args.zig");
31const test_while = @import("cases/while.zig");32const test_while = @import("cases/while.zig");