diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 73868db76..d43a88555 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -33,7 +33,7 @@ typedef uint64_t BitSize; #define INITIAL_SYMBOL_MAP 0x10000 #define INITIAL_GENERIC_SYMBOL_MAP 0x1000 #define MAX_MACRO_ITERATIONS 0xFFFFFF -#define MAX_PARAMS 512 +#define MAX_PARAMS 127 #define MAX_BITSTRUCT 0x1000 #define MAX_MEMBERS ((MemberIndex)(((uint64_t)2) << 28)) #define MAX_ALIGNMENT ((MemberIndex)(((uint64_t)2) << 28)) @@ -222,11 +222,19 @@ typedef struct ArraySize len; } TypeArray; +typedef struct +{ + bool nodiscard : 1; + bool maydiscard: 1; +} FunctionAttributes; typedef struct { + FunctionAttributes attrs; + Module *module; + Decl** params; struct FunctionPrototype_ *prototype; -} TypeFunc; +} TypeFunction; struct Type_ { @@ -245,8 +253,8 @@ struct Type_ TypeBuiltin builtin; // Type[], Type[*], Type[123], Type[<123>] or Type<[123]> TypeArray array; - // fn Type1(Type2, Type3, ...) throws Err1, Err2, ... - TypeFunc func; + // fn TypeR Type1(Type2, Type3, ...) + TypeFunction function; // Type* Type *pointer; // Failable @@ -434,11 +442,12 @@ typedef enum } Variadic; + typedef struct FunctionSignature_ { + FunctionAttributes attrs; Variadic variadic : 3; unsigned vararg_index : 10; - bool has_default : 1; bool use_win64 : 1; bool is_pure : 1; CallABI abi : 8; @@ -457,8 +466,6 @@ typedef struct bool attr_noinline : 1; bool attr_extname : 1; bool attr_naked : 1; - bool attr_nodiscard : 1; - bool attr_maydiscard: 1; }; TypeInfoId type_parent; FunctionSignature function_signature; @@ -1606,7 +1613,8 @@ typedef struct FunctionPrototype_ bool ret_by_ref : 1; unsigned short vararg_index; Type *rtype; - Type **params; + Type **param_types; + Decl **param_copy; Type **varargs; Type *ret_by_ref_type; Type *abi_ret_type; @@ -1614,7 +1622,12 @@ typedef struct FunctionPrototype_ ABIArgInfo *ret_by_ref_abi_info; ABIArgInfo **abi_args; ABIArgInfo **abi_varargs; - void *tb_prototype; + union + { + void *tb_prototype; + void *llvm_prototype; + }; + Type *raw_type; } FunctionPrototype; typedef struct @@ -2104,6 +2117,7 @@ Type *type_find_largest_union_element(Type *type); Type *type_find_max_type(Type *type, Type *other); Type *type_find_max_type_may_fail(Type *type, Type *other); Type *type_abi_find_single_struct_element(Type *type); +Module *type_base_module(Type *type); bool type_is_valid_for_vector(Type *type); Type *type_get_array(Type *arr_type, ArraySize len); Type *type_get_indexed_type(Type *type); diff --git a/src/compiler/llvm_codegen_c_abi_aarch64.c b/src/compiler/llvm_codegen_c_abi_aarch64.c index 81c3d6315..0d218f9d4 100644 --- a/src/compiler/llvm_codegen_c_abi_aarch64.c +++ b/src/compiler/llvm_codegen_c_abi_aarch64.c @@ -162,8 +162,8 @@ void c_abi_func_create_aarch64(FunctionPrototype *prototype) prototype->ret_by_ref_abi_info = aarch64_classify_argument_type(type_get_ptr(type_flatten(prototype->ret_by_ref_type))); } - Type **params = prototype->params; - unsigned param_count = vec_size(prototype->params); + Type **params = prototype->param_types; + unsigned param_count = vec_size(prototype->param_types); if (param_count) { ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * param_count); diff --git a/src/compiler/llvm_codegen_c_abi_riscv.c b/src/compiler/llvm_codegen_c_abi_riscv.c index a1c4bef3b..10fb47cca 100644 --- a/src/compiler/llvm_codegen_c_abi_riscv.c +++ b/src/compiler/llvm_codegen_c_abi_riscv.c @@ -297,6 +297,6 @@ void c_abi_func_create_riscv(FunctionPrototype *prototype) true, &arg_gprs_left, &arg_fprs_left); } - prototype->abi_args = riscv_create_params(prototype->params, true, &arg_gprs_left, &arg_fprs_left); + prototype->abi_args = riscv_create_params(prototype->param_types, true, &arg_gprs_left, &arg_fprs_left); prototype->abi_varargs = riscv_create_params(prototype->varargs, false, &arg_gprs_left, &arg_fprs_left); } diff --git a/src/compiler/llvm_codegen_c_abi_wasm.c b/src/compiler/llvm_codegen_c_abi_wasm.c index dd6ec2fca..5f42b0031 100644 --- a/src/compiler/llvm_codegen_c_abi_wasm.c +++ b/src/compiler/llvm_codegen_c_abi_wasm.c @@ -71,6 +71,6 @@ void c_abi_func_create_wasm(FunctionPrototype *prototype) prototype->ret_by_ref_abi_info = wasm_classify_argument_type(type_get_ptr(prototype->ret_by_ref_type)); } - prototype->abi_args = wasm_create_params(prototype->params); + prototype->abi_args = wasm_create_params(prototype->param_types); prototype->abi_varargs = wasm_create_params(prototype->varargs); } \ No newline at end of file diff --git a/src/compiler/llvm_codegen_c_abi_win64.c b/src/compiler/llvm_codegen_c_abi_win64.c index 0714ade2d..f24c19850 100644 --- a/src/compiler/llvm_codegen_c_abi_win64.c +++ b/src/compiler/llvm_codegen_c_abi_win64.c @@ -107,8 +107,8 @@ void win64_vector_call_args(Regs *regs, FunctionPrototype *prototype, bool is_ve { static const unsigned max_param_vector_calls_as_reg = 6; unsigned count = 0; - Type **params = prototype->params; - unsigned param_count = vec_size(prototype->params); + Type **params = prototype->param_types; + unsigned param_count = vec_size(prototype->param_types); if (param_count) { ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * param_count); @@ -199,6 +199,6 @@ void c_abi_func_create_win64(FunctionPrototype *prototype) return; } - prototype->abi_args = win64_create_params(prototype->params, ®s, is_vector_call, is_reg_call); + prototype->abi_args = win64_create_params(prototype->param_types, ®s, is_vector_call, is_reg_call); prototype->abi_varargs = win64_create_params(prototype->varargs, ®s, is_vector_call, is_reg_call); } \ No newline at end of file diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index e0a9ca14f..19d43a5c7 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -904,8 +904,8 @@ void c_abi_func_create_x64(FunctionPrototype *prototype) prototype->ret_by_ref_abi_info = x64_classify_parameter(type_get_ptr(type_lowering(prototype->ret_by_ref_type)), &available_registers, is_regcall, NAMED); } - Type **params = prototype->params; - unsigned param_count = vec_size(prototype->params); + Type **params = prototype->param_types; + unsigned param_count = vec_size(prototype->param_types); if (param_count) { ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * param_count); diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 489295243..82778a5fb 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -682,8 +682,8 @@ void c_abi_func_create_x86(FunctionPrototype *prototype) { FATAL_ERROR("X86 vector call not supported"); } - prototype->abi_args = x86_create_params(prototype->call_abi, prototype->params, ®s); - prototype->abi_varargs = x86_create_params(prototype->call_abi, prototype->params, ®s); + prototype->abi_args = x86_create_params(prototype->call_abi, prototype->param_types, ®s); + prototype->abi_varargs = x86_create_params(prototype->call_abi, prototype->param_types, ®s); } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 56959c721..8bcc5122e 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -501,11 +501,11 @@ static LLVMMetadataRef llvm_debug_vector_type(GenContext *c, Type *type) static LLVMMetadataRef llvm_debug_func_type(GenContext *c, Type *type) { - FunctionPrototype *prototype = type->func.prototype; + FunctionPrototype *prototype = type->function.prototype; // 1. Generate all the parameter types, this may cause this function to be called again! - VECEACH(prototype->params, i) + VECEACH(prototype->param_types, i) { - llvm_get_debug_type(c, prototype->params[i]); + llvm_get_debug_type(c, prototype->param_types[i]); } // 2. We might be done! if (type->backend_debug_type) return type->backend_debug_type; @@ -514,9 +514,9 @@ static LLVMMetadataRef llvm_debug_func_type(GenContext *c, Type *type) static LLVMMetadataRef *buffer = NULL; vec_resize(buffer, 0); vec_add(buffer, llvm_get_debug_type(c, prototype->rtype)); - VECEACH(prototype->params, i) + VECEACH(prototype->param_types, i) { - vec_add(buffer, llvm_get_debug_type(c, prototype->params[i])); + vec_add(buffer, llvm_get_debug_type(c, prototype->param_types[i])); } return LLVMDIBuilderCreateSubroutineType(c->debug.builder, c->debug.file, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 675fa4739..999afd658 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -4645,7 +4645,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) Type *type = function->type->canonical->pointer; // 1b. Find the type signature using the underlying pointer. - prototype = type->func.prototype; + prototype = type->function.prototype; // 1c. Evaluate the pointer expression. BEValue func_value; @@ -4665,14 +4665,14 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) always_inline = function_decl->func_decl.attr_inline; // 2b. Set signature, function and function type - prototype = function_decl->type->func.prototype; + prototype = function_decl->type->function.prototype; func = llvm_get_ref(c, function_decl); assert(func); func_type = llvm_get_type(c, function_decl->type); } LLVMValueRef *values = NULL; - Type **params = prototype->params; + Type **params = prototype->param_types; ABIArgInfo **abi_args = prototype->abi_args; unsigned param_count = vec_size(params); Expr **args = expr->call_expr.arguments; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index d7a5de9e2..28c6114ed 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -275,7 +275,7 @@ static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef valu void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable) { - FunctionPrototype *prototype = c->cur_func_decl->type->func.prototype; + FunctionPrototype *prototype = c->cur_func_decl->type->function.prototype; ABIArgInfo *info = prototype->ret_abi_info; // If we have a failable it's always the return argument, so we need to copy @@ -387,7 +387,7 @@ DIRECT_RETURN: void llvm_emit_return_implicit(GenContext *c) { - Type *rtype_real = c->cur_func_decl->type->func.prototype->rtype; + Type *rtype_real = c->cur_func_decl->type->function.prototype->rtype; if (type_lowering(type_no_optional(rtype_real)) != type_void) { LLVMBuildUnreachable(c->builder); @@ -445,7 +445,7 @@ void llvm_emit_function_body(GenContext *c, Decl *decl) LLVMValueRef alloca_point = LLVMBuildAlloca(c->builder, LLVMInt32TypeInContext(c->context), "alloca_point"); c->alloca_point = alloca_point; - FunctionPrototype *prototype = decl->type->func.prototype; + FunctionPrototype *prototype = decl->type->function.prototype; unsigned arg = 0; if (emit_debug) @@ -612,12 +612,12 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl) LLVMValueRef function = llvm_get_ref(c, decl); decl->backend_ref = function; - FunctionPrototype *prototype = decl->type->func.prototype; + FunctionPrototype *prototype = decl->type->function.prototype; ABIArgInfo *ret_abi_info = prototype->ret_abi_info; llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0); - unsigned params = vec_size(prototype->params); + unsigned params = vec_size(prototype->param_types); if (prototype->ret_by_ref) { ABIArgInfo *info = prototype->ret_by_ref_abi_info; diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index f5d552ae5..02820335f 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -181,7 +181,7 @@ static inline void llvm_emit_return(GenContext *c, Ast *ast) LLVMBasicBlockRef error_return_block = NULL; LLVMValueRef error_out = NULL; - if (type_is_optional(c->cur_func_decl->type->func.prototype->rtype)) + if (type_is_optional(c->cur_func_decl->type->function.prototype->rtype)) { error_return_block = llvm_basic_block_new(c, "err_retblock"); error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr"); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index c2f3aaefb..d73be27f6 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -286,9 +286,9 @@ LLVMTypeRef llvm_update_prototype_abi(GenContext *context, FunctionPrototype *pr } // Add in all of the required arguments. - VECEACH(prototype->params, i) + VECEACH(prototype->param_types, i) { - add_func_type_param(context, prototype->params[i], prototype->abi_args[i], params); + add_func_type_param(context, prototype->param_types[i], prototype->abi_args[i], params); } VECEACH(prototype->varargs, i) @@ -302,7 +302,7 @@ LLVMTypeRef llvm_func_type(GenContext *context, FunctionPrototype *prototype) { LLVMTypeRef *params = NULL; LLVMTypeRef ret = llvm_update_prototype_abi(context, prototype, ¶ms); - return LLVMFunctionType(ret, params, vec_size(params), prototype->variadic == VARIADIC_RAW); + return prototype->llvm_prototype = LLVMFunctionType(ret, params, vec_size(params), prototype->variadic == VARIADIC_RAW); } @@ -344,7 +344,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case TYPE_BITSTRUCT: return any_type->backend_type = llvm_type_from_decl(c, any_type->decl); case TYPE_FUNC: - return any_type->backend_type = llvm_func_type(c, any_type->func.prototype); + return any_type->backend_type = llvm_func_type(c, any_type->function.prototype); case TYPE_VOID: return any_type->backend_type = LLVMVoidTypeInContext(c->context); case TYPE_F64: @@ -456,51 +456,6 @@ LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type) return LLVMIntTypeInContext(c->context, type.int_bits_plus_1 - 1); } -static inline Module *type_base_module(Type *type) -{ - RETRY: - switch (type->type_kind) - { - case TYPE_POISONED: - case TYPE_VOID: - case ALL_INTS: - case ALL_FLOATS: - case TYPE_BOOL: - case TYPE_ANY: - case TYPE_ANYERR: - case TYPE_TYPEID: - return NULL; - case TYPE_POINTER: - type = type->pointer; - goto RETRY; - case TYPE_ENUM: - case TYPE_FUNC: - case TYPE_STRUCT: - case TYPE_UNION: - case TYPE_BITSTRUCT: - case TYPE_FAULTTYPE: - case TYPE_DISTINCT: - return type->decl->unit->module; - case TYPE_TYPEDEF: - type = type->canonical; - goto RETRY; - case TYPE_ARRAY: - case TYPE_SUBARRAY: - case TYPE_INFERRED_ARRAY: - case TYPE_FLEXIBLE_ARRAY: - case TYPE_VECTOR: - type = type->array.base; - goto RETRY; - case TYPE_FAILABLE: - type = type->failable; - goto RETRY; - case TYPE_UNTYPED_LIST: - case TYPE_FAILABLE_ANY: - case TYPE_TYPEINFO: - UNREACHABLE - } - UNREACHABLE -} static inline LLVMValueRef llvm_generate_temp_introspection_global(GenContext *c, Type *type) { @@ -739,10 +694,12 @@ LLVMValueRef llvm_get_typeid(GenContext *c, Type *type) case TYPE_UNION: return llvm_get_introspection_for_struct_union(c, type); case TYPE_FUNC: - { - LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); - return llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_FUNC, NULL, 0, NULL, false); - } + if (type->function.prototype->raw_type == type) + { + LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); + return llvm_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_FUNC, NULL, 0, NULL, false); + } + return llvm_get_typeid(c, type->function.prototype->raw_type); case TYPE_BITSTRUCT: { LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 563b42cc5..4420d85e3 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -485,6 +485,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, if ((type_is_integer(to_type) && type_size(to_type) >= type_size(type_iptr)) || to_type == type_bool || to_kind == TYPE_POINTER) return true; // Special subarray conversion: someType[N]* -> someType[] if (to_kind == TYPE_SUBARRAY && from_type->pointer->type_kind == TYPE_ARRAY && from_type->pointer->array.base == to_type->array.base) return true; + // Special function pointer conversion return false; case TYPE_ANY: return to_kind == TYPE_POINTER; @@ -605,17 +606,23 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool // For void* on either side, no checks. if (to == type_voidptr || from == type_voidptr) return true; - // Special handling of int* = int[4]* - if (from->pointer->type_kind == TYPE_ARRAY || from->pointer->type_kind == TYPE_FLEXIBLE_ARRAY) + Type *from_pointee = from->pointer; + + if (from_pointee->type_kind == TYPE_FUNC && to->type_kind == TYPE_POINTER && to->pointer->type_kind == TYPE_FUNC) { - if (type_is_subtype(to->pointer, from->pointer->array.base)) + return to->pointer->function.prototype->raw_type == from_pointee->function.prototype->raw_type; + } + // Special handling of int* = int[4]* + if (from_pointee->type_kind == TYPE_ARRAY || from_pointee->type_kind == TYPE_FLEXIBLE_ARRAY) + { + if (type_is_subtype(to->pointer, from_pointee->array.base)) { return true; } } // Use subtype matching - return type_is_subtype(to->pointer, from->pointer); + return type_is_subtype(to->pointer, from_pointee); } return false; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 9589c387b..f262031e2 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -581,9 +581,8 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl) } -static inline bool sema_analyse_function_param(SemaContext *context, Decl *param, bool is_function, bool *has_default) +static inline bool sema_analyse_function_param(SemaContext *context, Decl *param) { - *has_default = false; param->unit = context->unit; assert(param->decl_kind == DECL_VAR); // We need to check that the parameters are not typeless nor are of any macro parameter kind. @@ -606,11 +605,6 @@ static inline bool sema_analyse_function_param(SemaContext *context, Decl *param param->var.type_info->type = type_get_subarray(param->var.type_info->type); } param->type = param->var.type_info->type; - if (param->var.init_expr && !is_function) - { - SEMA_ERROR(param->var.init_expr, "Function types may not have default arguments."); - return false; - } if (param->var.init_expr) { Expr *expr = param->var.init_expr; @@ -619,78 +613,87 @@ static inline bool sema_analyse_function_param(SemaContext *context, Decl *param { if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false; } - *has_default = true; } param->alignment = type_abi_alignment(param->type); return true; } -static inline Type *sema_analyse_function_signature(SemaContext *context, CallABI abi, FunctionSignature *signature, bool is_real_function) +static inline Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallABI abi, FunctionSignature *signature, bool is_real_function) { - bool all_ok = true; - all_ok = sema_resolve_type_info(context, type_infoptr(signature->returntype)) && all_ok; + // Get param count and variadic type + Variadic variadic_type = signature->variadic; + Decl **params = signature->params; + unsigned param_count = vec_size(params); + + bool all_ok = sema_resolve_type_info(context, type_infoptr(signature->returntype)); // We don't support more than MAX_PARAMS number of params. This makes everything sane. - if (vec_size(signature->params) > MAX_PARAMS) + if (param_count > MAX_PARAMS) { - SEMA_ERROR(signature->params[MAX_PARAMS], "Number of params exceeds %d which is unsupported.", MAX_PARAMS); + if (variadic_type != VARIADIC_NONE) + { + SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d.", MAX_PARAMS); + return NULL; + } + SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d. To accept more arguments, consider using varargs.", MAX_PARAMS); return NULL; } - // Get param count and variadic type - Variadic variadic_type = signature->variadic; - unsigned param_count = vec_size(signature->params); - Decl **params = signature->params; Type **types = NULL; - bool reached_vararg = false; - + int vararg_index = -1; for (unsigned i = 0; i < param_count; i++) { Decl *param = params[i]; // We might run into a raw vararg if (!param) { - // Just skip, we'll remove this parameter later. assert(variadic_type == VARIADIC_RAW); - reached_vararg = true; + vararg_index = i; continue; } assert(param->resolve_status == RESOLVE_NOT_DONE && "The param shouldn't have been resolved yet."); param->resolve_status = RESOLVE_RUNNING; - bool has_default; // Analyse the param - if (!sema_analyse_function_param(context, param, is_real_function, &has_default)) + if (!sema_analyse_function_param(context, param)) { decl_poison(param); all_ok = false; continue; } - if (reached_vararg) + if (vararg_index > -1) { - // If we already reached a vararg (as a previous argument) and we have a - // parameter without a name. - if (!param->name) - { - SEMA_ERROR(param, "A parameter name was expected, as parameters after varargs must be named."); - decl_poison(param); - return NULL; - } if (variadic_type == VARIADIC_RAW) { SEMA_ERROR(param, "C-style varargs cannot be followed by regular parameters."); return NULL; } + + // If we already reached a vararg (as a previous argument) and we have a + // parameter without a name then that is an error. + if (!param->name) + { + SEMA_ERROR(param, "A parameter name was expected, as parameters after varargs must always be named."); + decl_poison(param); + all_ok = false; + continue; + } } // Disallow "void" args and repeating the same parameter name. // This must be done after checking raw varargs if (!sema_check_param_uniqueness_and_type(params, param, i, param_count)) { all_ok = false; - continue; } // Update whether this was a vararg, and update "default" for the signature. - reached_vararg |= param->var.vararg; - signature->has_default = signature->has_default || has_default; + if (param->var.vararg) + { + if (vararg_index > -1) + { + SEMA_ERROR(param, "A function may not have more than one vararg."); + all_ok = false; + } + vararg_index = i; + } // Resolution is done. param->resolve_status = RESOLVE_DONE; // Add it to the type for the type signature. @@ -699,19 +702,28 @@ static inline Type *sema_analyse_function_signature(SemaContext *context, CallAB // Remove the last empty value. if (variadic_type == VARIADIC_RAW) { - assert(VECLAST(params) == NULL && "The last parameter must have been a raw variadic."); - vec_pop(signature->params); + assert(vararg_index >= 0); + assert(!params[vararg_index] && "The last parameter must have been a raw variadic."); + assert(vararg_index == param_count - 1); + vec_pop(params); } - if (!all_ok) return NULL; - return type_get_func(signature, abi); + if (!all_ok) return NULL; + Type *raw_type = type_get_func(signature, abi); + Type *type = type_new(TYPE_FUNC, parent->name); + type->canonical = type; + type->function.attrs = signature->attrs; + type->function.module = parent->unit->module; + type->function.params = signature->params; + type->function.prototype = raw_type->function.prototype; + return type; } static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl) { if (decl->typedef_decl.is_func) { - Type *func_type = sema_analyse_function_signature(context, CALL_C, &decl->typedef_decl.function_signature, false); + Type *func_type = sema_analyse_function_signature(context, decl, CALL_C, &decl->typedef_decl.function_signature, false); if (!func_type) return false; decl->type->canonical = type_get_ptr(func_type); return true; @@ -732,7 +744,7 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl) { if (decl->distinct_decl.typedef_decl.is_func) { - Type *func_type = sema_analyse_function_signature(context, CALL_C, &decl->distinct_decl.typedef_decl.function_signature, false); + Type *func_type = sema_analyse_function_signature(context, decl, CALL_C, &decl->distinct_decl.typedef_decl.function_signature, false); if (!func_type) return false; decl->distinct_decl.base_type = type_get_ptr(func_type); return true; @@ -1469,7 +1481,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, decl->macro_decl.attr_nodiscard = true; break; } - decl->func_decl.attr_nodiscard = true; + decl->func_decl.function_signature.attrs.nodiscard = true; break; case ATTRIBUTE_MAYDISCARD: if (domain == ATTR_MACRO) @@ -1477,7 +1489,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, decl->macro_decl.attr_maydiscard = true; break; } - decl->func_decl.attr_maydiscard = true; + decl->func_decl.function_signature.attrs.maydiscard = true; break; case ATTRIBUTE_INLINE: decl->func_decl.attr_inline = true; @@ -1871,13 +1883,13 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl) if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FUNC)) return decl_poison(decl); - Type *func_type = sema_analyse_function_signature(context, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true); + Type *func_type = sema_analyse_function_signature(context, decl, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true); decl->type = func_type; if (!func_type) return decl_poison(decl); TypeInfo *rtype_info = type_infoptr(decl->func_decl.function_signature.returntype); assert(rtype_info); Type *rtype = rtype_info->type->canonical; - if (decl->func_decl.attr_nodiscard) + if (decl->func_decl.function_signature.attrs.nodiscard) { if (rtype == type_void) { @@ -1885,7 +1897,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl) return decl_poison(decl); } } - if (decl->func_decl.attr_maydiscard) + if (decl->func_decl.function_signature.attrs.maydiscard) { if (!type_is_optional(rtype)) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index b54d089ed..a7ca8f9c1 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1477,12 +1477,6 @@ INLINE bool sema_expand_call_arguments(SemaContext *context, CalledDecl *callee, // 3. Handle named parameters if (arg->expr_kind == EXPR_DESIGNATOR) { - if (is_func_ptr) - { - SEMA_ERROR(arg, "Named parameters are not allowed with function pointer calls."); - return false; - } - // Find the location of the parameter. int index = find_index_of_named_parameter(params, arg); @@ -1562,7 +1556,7 @@ INLINE bool sema_expand_call_arguments(SemaContext *context, CalledDecl *callee, // 17a. Assigned a value - skip if (actual_args[i]) continue; if (i == vararg_index && variadic != VARIADIC_NONE) continue; - if (is_func_ptr) goto FAIL_MISSING; + // 17b. Set the init expression. Decl *param = params[i]; Expr *init_expr = param->var.init_expr; @@ -1586,13 +1580,11 @@ INLINE bool sema_expand_call_arguments(SemaContext *context, CalledDecl *callee, continue; } -FAIL_MISSING: - // 17c. Vararg not set? That's fine. - if (param && params[i]->var.vararg) continue; + if (params[i]->var.vararg) continue; // 17d. Argument missing, that's bad. - if (!has_named || is_func_ptr || !params[i]->name) + if (!has_named || !params[i]->name) { if (func_param_count == 1) { @@ -1601,6 +1593,11 @@ FAIL_MISSING: } if (variadic != VARIADIC_NONE && i > vararg_index) { + if (!param[i].name) + { + sema_error_at_after(args[num_args - 1]->span, "Argument #%d is not set.", i); + return false; + } sema_error_at_after(args[num_args - 1]->span, "Expected '.%s = ...' after this argument.", params[i]->name); return false; } @@ -1849,7 +1846,7 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr } return true; } -static inline bool sema_expr_analyse_func_invocation(SemaContext *context, FunctionPrototype *prototype, +static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Type *type, FunctionSignature *sig, Expr *expr, Decl *decl, Expr *struct_var, bool failable, const char *name) { @@ -1859,11 +1856,11 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Funct .func_pointer = sig ? 0 : 1, .block_parameter = NULL, .struct_var = struct_var, - .params = sig ? sig->params : NULL, - .param_types = prototype->params, - .param_count = vec_size(prototype->params), - .variadic = prototype->variadic, - .vararg_index = prototype->vararg_index + .params = type->function.params, + .param_types = type->function.prototype->param_types, + .param_count = vec_size(type->function.prototype->param_types), + .variadic = type->function.prototype->variadic, + .vararg_index = type->function.prototype->vararg_index }; if (context->current_function_pure && (!sig || !sig->is_pure) && !expr->call_expr.attr_pure) { @@ -1874,16 +1871,16 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Funct bool is_unused = expr->call_expr.result_unused; if (!sema_expr_analyse_call_invocation(context, expr, callee, &failable)) return false; - Type *rtype = prototype->rtype; + Type *rtype = type->function.prototype->rtype; if (is_unused && rtype != type_void && decl && decl->decl_kind == DECL_FUNC) { - if (decl->func_decl.attr_nodiscard) + if (decl->func_decl.function_signature.attrs.nodiscard) { SEMA_ERROR(expr, "The result of the function must be used."); return false; } - if (type_is_optional(rtype) && !decl->func_decl.attr_maydiscard) + if (type_is_optional(rtype) && !decl->func_decl.function_signature.attrs.maydiscard) { SEMA_ERROR(expr, "The optional result of the macro must be used."); return false; @@ -1897,18 +1894,21 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Funct static inline bool sema_expr_analyse_var_call(SemaContext *context, Expr *expr, Type *func_ptr_type, bool failable) { - if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC) - { - SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(func_ptr_type)); - return false; - } + Decl *decl = NULL; + if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC) goto ERR; + Type *pointee = func_ptr_type->pointer; expr->call_expr.is_pointer_call = true; return sema_expr_analyse_func_invocation(context, - func_ptr_type->pointer->func.prototype, + pointee, NULL, expr, - NULL, NULL, failable, func_ptr_type->pointer->name); - + decl, + NULL, + failable, + func_ptr_type->pointer->name); +ERR: + SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(func_ptr_type)); + return false; } // Unify returns in a macro or expression block. @@ -2007,9 +2007,9 @@ static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr, { expr->call_expr.is_pointer_call = false; return sema_expr_analyse_func_invocation(context, - decl->type->func.prototype, + decl->type, &decl->func_decl.function_signature, - expr, + expr, decl, struct_var, failable, @@ -2850,7 +2850,7 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr) default: { Type *type = type_flatten_distinct(func_expr->type); - if (type->type_kind == TYPE_POINTER && type->pointer->type_kind == TYPE_FUNC) + if (type->type_kind == TYPE_POINTER) { decl = NULL; break; @@ -7552,15 +7552,19 @@ static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr) return true; } - // TODO type_is_builtin is wrong also this does not cover virtual. if (name_type == TOKEN_CT_NAMEOF || type_is_builtin(type->type_kind)) { expr_rewrite_to_string(expr, type->name); return true; } scratch_buffer_clear(); - scratch_buffer_append(type->decl->unit->module->name->module); - scratch_buffer_append("::"); + + Module *module = type_base_module(type); + if (module) + { + scratch_buffer_append(module->name->module); + scratch_buffer_append("::"); + } scratch_buffer_append(type->name); expr_rewrite_to_string(expr, scratch_buffer_copy()); return true; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 6924c966e..9bdc90ff7 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2545,7 +2545,7 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) { if (!decl_ok(func)) return false; FunctionSignature *signature = &func->func_decl.function_signature; - FunctionPrototype *prototype = func->type->func.prototype; + FunctionPrototype *prototype = func->type->function.prototype; context->current_function = func; context->current_function_pure = func->func_decl.function_signature.is_pure; context->rtype = prototype->rtype; diff --git a/src/compiler/types.c b/src/compiler/types.c index ce8bcfc4b..7fd555fb5 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -169,7 +169,7 @@ static void type_append_name_to_scratch(Type *type) UNREACHABLE break; case TYPE_FUNC: - type_append_func_to_scratch(type->func.prototype); + type_append_func_to_scratch(type->function.prototype); break; case TYPE_ARRAY: type_append_name_to_scratch(type->array.base); @@ -184,14 +184,14 @@ static void type_append_func_to_scratch(FunctionPrototype *prototype) { type_append_name_to_scratch(prototype->rtype); scratch_buffer_append_char('('); - unsigned elements = vec_size(prototype->params); + unsigned elements = vec_size(prototype->param_types); for (unsigned i = 0; i < elements; i++) { if (i > 0) { scratch_buffer_append_char(','); } - type_append_name_to_scratch(prototype->params[i]); + type_append_name_to_scratch(prototype->param_types[i]); } if (prototype->variadic == VARIADIC_RAW && elements > 0) { @@ -227,7 +227,7 @@ const char *type_to_error_string(Type *type) return type->name; case TYPE_FUNC: scratch_buffer_clear(); - type_append_func_to_scratch(type->func.prototype); + type_append_func_to_scratch(type->function.prototype); return str_printf("fn %s", scratch_buffer_to_string()); case TYPE_VECTOR: return str_printf("%s[<%llu>]", type_to_error_string(type->array.base), (unsigned long long)type->array.len); @@ -510,8 +510,37 @@ void type_mangle_introspect_name_to_buffer(Type *type) scratch_buffer_append_char('$'); type_mangle_introspect_name_to_buffer(type->array.base); return; - case TYPE_ENUM: case TYPE_FUNC: + if (type->function.module) + { + scratch_buffer_append(type->function.module->extname); + scratch_buffer_append_char('$'); + scratch_buffer_append(type->name); + } + else + { + size_t len = strlen(type->name); + for (size_t i = 0; i < len; i++) + { + char c = type->name[i]; + if (char_is_alphanum_(c)) + { + scratch_buffer_append_char(c); + continue; + } + if (c == '$') + { + scratch_buffer_append("$$"); + continue; + } + else + { + scratch_buffer_append_char('$'); + } + } + } + return; + case TYPE_ENUM: case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: @@ -1068,7 +1097,7 @@ static int compare_function(FunctionSignature *sig, FunctionPrototype *proto) { if (sig->variadic != proto->variadic) return -1; Decl **params = sig->params; - Type **other_params = proto->params; + Type **other_params = proto->param_types; unsigned param_count = vec_size(params); if (param_count != vec_size(other_params)) return -1; if (type_infoptr(sig->returntype)->type->canonical != proto->rtype->canonical) return -1; @@ -1103,19 +1132,41 @@ static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI a proto->ret_by_ref_type = proto->abi_ret_type = rtype; } proto->call_abi = abi; + if (param_count) { - Type **params = VECNEW(Type*, param_count); + Type **param_types = VECNEW(Type*, param_count); + Decl **param_copy = VECNEW(Decl*, param_count); for (unsigned i = 0; i < param_count; i++) { - vec_add(params, sig->params[i]->type); + Decl *decl = decl_copy(sig->params[i]); + decl->type = decl->type->canonical; + decl->var.type_info = NULL; + decl->var.init_expr = NULL; + decl->name = NULL; + vec_add(param_types, decl->type); + vec_add(param_copy, decl); } - proto->params = params; + proto->param_types = param_types; + proto->param_copy = param_copy; } c_abi_func_create(proto); - Type *type = type_new(TYPE_FUNC, "#Function"); - type->func.prototype = proto; + scratch_buffer_clear(); + scratch_buffer_append("fn "); + type_append_name_to_scratch(proto->rtype); + scratch_buffer_append_char('('); + foreach(Type*, proto->param_types) + { + if (foreach_index != 0) scratch_buffer_append(", "); + type_append_name_to_scratch(val); + } + scratch_buffer_append_char(')'); + Type *type = type_new(TYPE_FUNC, scratch_buffer_interned()); + proto->raw_type = type; + type->function.prototype = proto; + type->function.module = NULL; + type->function.params = proto->param_copy; type->canonical = type; entry->key = hash; entry->value = type; @@ -1165,7 +1216,7 @@ Type *type_get_func(FunctionSignature *signature, CallABI abi) { return func_create_new_func_proto(signature, abi, hash, entry); } - if (entry->key == hash && compare_function(signature, entry->value->func.prototype) == 0) + if (entry->key == hash && compare_function(signature, entry->value->function.prototype) == 0) { return entry->value; } @@ -1320,7 +1371,7 @@ bool type_is_subtype(Type *type, Type *possible_subtype) { if (type == possible_subtype) return true; if (type->type_kind != possible_subtype->type_kind) return false; - if (type->decl->decl_kind != DECL_STRUCT) return false; + if (type->type_kind != TYPE_STRUCT) return false; if (!possible_subtype->decl->strukt.members) return false; @@ -1599,6 +1650,10 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_ANYERR: return type_anyerr; case TYPE_FUNC: + if (other->type_kind != TYPE_FUNC) return NULL; + other = other->function.prototype->raw_type; + type = other->function.prototype->raw_type; + return other == type ? type : NULL; case TYPE_UNION: case TYPE_TYPEID: case TYPE_STRUCT: @@ -1730,4 +1785,51 @@ unsigned type_get_introspection_kind(TypeKind kind) return 0; } UNREACHABLE -} \ No newline at end of file +} + +Module *type_base_module(Type *type) +{ + RETRY: + switch (type->type_kind) + { + case TYPE_POISONED: + case TYPE_VOID: + case ALL_INTS: + case ALL_FLOATS: + case TYPE_BOOL: + case TYPE_ANY: + case TYPE_ANYERR: + case TYPE_TYPEID: + return NULL; + case TYPE_POINTER: + type = type->pointer; + goto RETRY; + case TYPE_FUNC: + return type->function.module; + case TYPE_ENUM: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_BITSTRUCT: + case TYPE_FAULTTYPE: + case TYPE_DISTINCT: + return type->decl->unit->module; + case TYPE_TYPEDEF: + type = type->canonical; + goto RETRY; + case TYPE_ARRAY: + case TYPE_SUBARRAY: + case TYPE_INFERRED_ARRAY: + case TYPE_FLEXIBLE_ARRAY: + case TYPE_VECTOR: + type = type->array.base; + goto RETRY; + case TYPE_FAILABLE: + type = type->failable; + goto RETRY; + case TYPE_UNTYPED_LIST: + case TYPE_FAILABLE_ANY: + case TYPE_TYPEINFO: + UNREACHABLE + } + UNREACHABLE +} diff --git a/src/version.h b/src/version.h index 71925510f..b8dc8934e 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.26" \ No newline at end of file +#define COMPILER_VERSION "0.3.27" \ No newline at end of file diff --git a/test/test_suite/functions/func_ptr_conversions_and_names.c3t b/test/test_suite/functions/func_ptr_conversions_and_names.c3t new file mode 100644 index 000000000..b75a91302 --- /dev/null +++ b/test/test_suite/functions/func_ptr_conversions_and_names.c3t @@ -0,0 +1,358 @@ +// #target: macos-x64 +module test; +import std::io; +define Func = fn int(int y); +define FuncOther = fn bool(char*); +define FuncSame = fn int(int z = 444); + +fn int test(int a) { return a; } +fn int test2(int b = 3) { return b; } + +fn int! test3(int b = 3) { return b; } +fn int! test4(int b = 3) { return b; } + +fn void main() +{ + Func a = &test; + Func b = &test2; + io::printfln("%d", a(.y = 123)); + io::printfln("%d", (&test2)()); + FuncSame z = &test2; + io::printfln("%d", z()); + io::printfln("%s", $qnameof($typeof(b ? &test2 : &test))); + io::printfln("%s", $nameof($typeof(b ? &test2 : &test))); + io::printfln("%s", $qnameof($typeof(&test2))); + io::printfln("%s", $nameof($typeof(&test2))); + io::printfln("%s", $nameof($typeof(b ? &test4 : &test3))); + + $typeof(b ? &test2 : &test) y = &test2; + typeid zfoke = $typeof(y).typeid; +} + + +/* #expect: test.ll + +@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@"ct$int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@.str.2 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.4 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1 +@"ct$char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$a12$char" = linkonce constant %.introspect { i8 15, i64 12, i64 ptrtoint (%.introspect* @"ct$char" to i64), i64 12, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a12$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (%.introspect* @"ct$a12$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.5 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.6 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1 +@.str.7 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.8 = private unnamed_addr constant [13 x i8] c"test::test2*\00", align 1 +@.str.9 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.10 = private unnamed_addr constant [7 x i8] c"test2*\00", align 1 +@"ct$a6$char" = linkonce constant %.introspect { i8 15, i64 6, i64 ptrtoint (%.introspect* @"ct$char" to i64), i64 6, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a6$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (%.introspect* @"ct$a6$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.12 = private unnamed_addr constant [14 x i8] c"fn int!(int)*\00", align 1 +@"ct$a13$char" = linkonce constant %.introspect { i8 15, i64 13, i64 ptrtoint (%.introspect* @"ct$char" to i64), i64 13, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a13$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (%.introspect* @"ct$a13$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$fn$int$int$" = linkonce constant %.introspect { i8 13, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$p$fn$int$int$" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (%.introspect* @"ct$fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 + + +define void @test_main() #0 { +entry: + %a = alloca i32 (i32)*, align 8 + %b = alloca i32 (i32)*, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %taddr1 = alloca i32, align 4 + %retparam4 = alloca i64, align 8 + %taddr5 = alloca %"char[]", align 8 + %vararg8 = alloca %"variant[]", align 8 + %varargslots9 = alloca [1 x %variant], align 16 + %taddr10 = alloca i32, align 4 + %z = alloca i32 (i32)*, align 8 + %retparam16 = alloca i64, align 8 + %taddr17 = alloca %"char[]", align 8 + %vararg20 = alloca %"variant[]", align 8 + %varargslots21 = alloca [1 x %variant], align 16 + %taddr22 = alloca i32, align 4 + %retparam28 = alloca i64, align 8 + %taddr29 = alloca %"char[]", align 8 + %vararg32 = alloca %"variant[]", align 8 + %varargslots33 = alloca [1 x %variant], align 16 + %taddr34 = alloca [12 x i8]*, align 8 + %retparam40 = alloca i64, align 8 + %taddr41 = alloca %"char[]", align 8 + %vararg44 = alloca %"variant[]", align 8 + %varargslots45 = alloca [1 x %variant], align 16 + %taddr46 = alloca [12 x i8]*, align 8 + %retparam52 = alloca i64, align 8 + %taddr53 = alloca %"char[]", align 8 + %vararg56 = alloca %"variant[]", align 8 + %varargslots57 = alloca [1 x %variant], align 16 + %taddr58 = alloca [12 x i8]*, align 8 + %retparam64 = alloca i64, align 8 + %taddr65 = alloca %"char[]", align 8 + %vararg68 = alloca %"variant[]", align 8 + %varargslots69 = alloca [1 x %variant], align 16 + %taddr70 = alloca [6 x i8]*, align 8 + %retparam76 = alloca i64, align 8 + %taddr77 = alloca %"char[]", align 8 + %vararg80 = alloca %"variant[]", align 8 + %varargslots81 = alloca [1 x %variant], align 16 + %taddr82 = alloca [13 x i8]*, align 8 + %y = alloca i32 (i32)*, align 8 + %zfoke = alloca i64, align 8 + store i32 (i32)* @test_test, i32 (i32)** %a, align 8 + store i32 (i32)* @test_test2, i32 (i32)** %b, align 8 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i64 2 }, %"char[]"* %taddr, align 8 + %0 = bitcast %"char[]"* %taddr to { i8*, i64 }* + %1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %0, i32 0, i32 0 + %lo = load i8*, i8** %1, align 8 + %2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %0, i32 0, i32 1 + %hi = load i64, i64* %2, align 8 + %3 = load i32 (i32)*, i32 (i32)** %a, align 8 + %4 = call i32 %3(i32 123) + store i32 %4, i32* %taddr1, align 4 + %5 = bitcast i32* %taddr1 to i8* + %6 = insertvalue %variant undef, i8* %5, 0 + %7 = insertvalue %variant %6, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %8 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0 + store %variant %7, %variant* %8, align 16 + %9 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1 + store i64 1, i64* %9, align 8 + %10 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0 + %11 = bitcast [1 x %variant]* %varargslots to %variant* + store %variant* %11, %variant** %10, align 8 + %12 = bitcast %"variant[]"* %vararg to { i8*, i64 }* + %13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %12, i32 0, i32 0 + %lo2 = load i8*, i8** %13, align 8 + %14 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %12, i32 0, i32 1 + %hi3 = load i64, i64* %14, align 8 + %15 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3) + %not_err = icmp eq i64 %15, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, %"char[]"* %taddr5, align 8 + %16 = bitcast %"char[]"* %taddr5 to { i8*, i64 }* + %17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 0 + %lo6 = load i8*, i8** %17, align 8 + %18 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %16, i32 0, i32 1 + %hi7 = load i64, i64* %18, align 8 + %19 = call i32 @test_test2(i32 3) + store i32 %19, i32* %taddr10, align 4 + %20 = bitcast i32* %taddr10 to i8* + %21 = insertvalue %variant undef, i8* %20, 0 + %22 = insertvalue %variant %21, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %23 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots9, i64 0, i64 0 + store %variant %22, %variant* %23, align 16 + %24 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg8, i32 0, i32 1 + store i64 1, i64* %24, align 8 + %25 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg8, i32 0, i32 0 + %26 = bitcast [1 x %variant]* %varargslots9 to %variant* + store %variant* %26, %variant** %25, align 8 + %27 = bitcast %"variant[]"* %vararg8 to { i8*, i64 }* + %28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 0 + %lo11 = load i8*, i8** %28, align 8 + %29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 1 + %hi12 = load i64, i64* %29, align 8 + %30 = call i64 @std_io_printfln(i64* %retparam4, i8* %lo6, i64 %hi7, i8* %lo11, i64 %hi12) + %not_err13 = icmp eq i64 %30, 0 + br i1 %not_err13, label %after_check14, label %voiderr15 + +after_check14: ; preds = %voiderr + br label %voiderr15 + +voiderr15: ; preds = %after_check14, %voiderr + store i32 (i32)* @test_test2, i32 (i32)** %z, align 8 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i32 0, i32 0), i64 2 }, %"char[]"* %taddr17, align 8 + %31 = bitcast %"char[]"* %taddr17 to { i8*, i64 }* + %32 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %31, i32 0, i32 0 + %lo18 = load i8*, i8** %32, align 8 + %33 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %31, i32 0, i32 1 + %hi19 = load i64, i64* %33, align 8 + %34 = load i32 (i32)*, i32 (i32)** %z, align 8 + %35 = call i32 %34(i32 444) + store i32 %35, i32* %taddr22, align 4 + %36 = bitcast i32* %taddr22 to i8* + %37 = insertvalue %variant undef, i8* %36, 0 + %38 = insertvalue %variant %37, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %39 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots21, i64 0, i64 0 + store %variant %38, %variant* %39, align 16 + %40 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg20, i32 0, i32 1 + store i64 1, i64* %40, align 8 + %41 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg20, i32 0, i32 0 + %42 = bitcast [1 x %variant]* %varargslots21 to %variant* + store %variant* %42, %variant** %41, align 8 + %43 = bitcast %"variant[]"* %vararg20 to { i8*, i64 }* + %44 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %43, i32 0, i32 0 + %lo23 = load i8*, i8** %44, align 8 + %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %43, i32 0, i32 1 + %hi24 = load i64, i64* %45, align 8 + %46 = call i64 @std_io_printfln(i64* %retparam16, i8* %lo18, i64 %hi19, i8* %lo23, i64 %hi24) + %not_err25 = icmp eq i64 %46, 0 + br i1 %not_err25, label %after_check26, label %voiderr27 + +after_check26: ; preds = %voiderr15 + br label %voiderr27 + +voiderr27: ; preds = %after_check26, %voiderr15 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0), i64 2 }, %"char[]"* %taddr29, align 8 + %47 = bitcast %"char[]"* %taddr29 to { i8*, i64 }* + %48 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 0 + %lo30 = load i8*, i8** %48, align 8 + %49 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %47, i32 0, i32 1 + %hi31 = load i64, i64* %49, align 8 + store [12 x i8]* bitcast ([13 x i8]* @.str.4 to [12 x i8]*), [12 x i8]** %taddr34, align 8 + %50 = bitcast [12 x i8]** %taddr34 to i8* + %51 = insertvalue %variant undef, i8* %50, 0 + %52 = insertvalue %variant %51, i64 ptrtoint (%.introspect* @"ct$p$a12$char" to i64), 1 + %53 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots33, i64 0, i64 0 + store %variant %52, %variant* %53, align 16 + %54 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg32, i32 0, i32 1 + store i64 1, i64* %54, align 8 + %55 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg32, i32 0, i32 0 + %56 = bitcast [1 x %variant]* %varargslots33 to %variant* + store %variant* %56, %variant** %55, align 8 + %57 = bitcast %"variant[]"* %vararg32 to { i8*, i64 }* + %58 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %57, i32 0, i32 0 + %lo35 = load i8*, i8** %58, align 8 + %59 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %57, i32 0, i32 1 + %hi36 = load i64, i64* %59, align 8 + %60 = call i64 @std_io_printfln(i64* %retparam28, i8* %lo30, i64 %hi31, i8* %lo35, i64 %hi36) + %not_err37 = icmp eq i64 %60, 0 + br i1 %not_err37, label %after_check38, label %voiderr39 + +after_check38: ; preds = %voiderr27 + br label %voiderr39 + +voiderr39: ; preds = %after_check38, %voiderr27 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.5, i32 0, i32 0), i64 2 }, %"char[]"* %taddr41, align 8 + %61 = bitcast %"char[]"* %taddr41 to { i8*, i64 }* + %62 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %61, i32 0, i32 0 + %lo42 = load i8*, i8** %62, align 8 + %63 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %61, i32 0, i32 1 + %hi43 = load i64, i64* %63, align 8 + store [12 x i8]* bitcast ([13 x i8]* @.str.6 to [12 x i8]*), [12 x i8]** %taddr46, align 8 + %64 = bitcast [12 x i8]** %taddr46 to i8* + %65 = insertvalue %variant undef, i8* %64, 0 + %66 = insertvalue %variant %65, i64 ptrtoint (%.introspect* @"ct$p$a12$char" to i64), 1 + %67 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots45, i64 0, i64 0 + store %variant %66, %variant* %67, align 16 + %68 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg44, i32 0, i32 1 + store i64 1, i64* %68, align 8 + %69 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg44, i32 0, i32 0 + %70 = bitcast [1 x %variant]* %varargslots45 to %variant* + store %variant* %70, %variant** %69, align 8 + %71 = bitcast %"variant[]"* %vararg44 to { i8*, i64 }* + %72 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 0 + %lo47 = load i8*, i8** %72, align 8 + %73 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 1 + %hi48 = load i64, i64* %73, align 8 + %74 = call i64 @std_io_printfln(i64* %retparam40, i8* %lo42, i64 %hi43, i8* %lo47, i64 %hi48) + %not_err49 = icmp eq i64 %74, 0 + br i1 %not_err49, label %after_check50, label %voiderr51 + +after_check50: ; preds = %voiderr39 + br label %voiderr51 + +voiderr51: ; preds = %after_check50, %voiderr39 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.7, i32 0, i32 0), i64 2 }, %"char[]"* %taddr53, align 8 + %75 = bitcast %"char[]"* %taddr53 to { i8*, i64 }* + %76 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %75, i32 0, i32 0 + %lo54 = load i8*, i8** %76, align 8 + %77 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %75, i32 0, i32 1 + %hi55 = load i64, i64* %77, align 8 + store [12 x i8]* bitcast ([13 x i8]* @.str.8 to [12 x i8]*), [12 x i8]** %taddr58, align 8 + %78 = bitcast [12 x i8]** %taddr58 to i8* + %79 = insertvalue %variant undef, i8* %78, 0 + %80 = insertvalue %variant %79, i64 ptrtoint (%.introspect* @"ct$p$a12$char" to i64), 1 + %81 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots57, i64 0, i64 0 + store %variant %80, %variant* %81, align 16 + %82 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg56, i32 0, i32 1 + store i64 1, i64* %82, align 8 + %83 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg56, i32 0, i32 0 + %84 = bitcast [1 x %variant]* %varargslots57 to %variant* + store %variant* %84, %variant** %83, align 8 + %85 = bitcast %"variant[]"* %vararg56 to { i8*, i64 }* + %86 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 0 + %lo59 = load i8*, i8** %86, align 8 + %87 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 1 + %hi60 = load i64, i64* %87, align 8 + %88 = call i64 @std_io_printfln(i64* %retparam52, i8* %lo54, i64 %hi55, i8* %lo59, i64 %hi60) + %not_err61 = icmp eq i64 %88, 0 + br i1 %not_err61, label %after_check62, label %voiderr63 + +after_check62: ; preds = %voiderr51 + br label %voiderr63 + +voiderr63: ; preds = %after_check62, %voiderr51 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0), i64 2 }, %"char[]"* %taddr65, align 8 + %89 = bitcast %"char[]"* %taddr65 to { i8*, i64 }* + %90 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %89, i32 0, i32 0 + %lo66 = load i8*, i8** %90, align 8 + %91 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %89, i32 0, i32 1 + %hi67 = load i64, i64* %91, align 8 + store [6 x i8]* bitcast ([7 x i8]* @.str.10 to [6 x i8]*), [6 x i8]** %taddr70, align 8 + %92 = bitcast [6 x i8]** %taddr70 to i8* + %93 = insertvalue %variant undef, i8* %92, 0 + %94 = insertvalue %variant %93, i64 ptrtoint (%.introspect* @"ct$p$a6$char" to i64), 1 + %95 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots69, i64 0, i64 0 + store %variant %94, %variant* %95, align 16 + %96 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg68, i32 0, i32 1 + store i64 1, i64* %96, align 8 + %97 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg68, i32 0, i32 0 + %98 = bitcast [1 x %variant]* %varargslots69 to %variant* + store %variant* %98, %variant** %97, align 8 + %99 = bitcast %"variant[]"* %vararg68 to { i8*, i64 }* + %100 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %99, i32 0, i32 0 + %lo71 = load i8*, i8** %100, align 8 + %101 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %99, i32 0, i32 1 + %hi72 = load i64, i64* %101, align 8 + %102 = call i64 @std_io_printfln(i64* %retparam64, i8* %lo66, i64 %hi67, i8* %lo71, i64 %hi72) + %not_err73 = icmp eq i64 %102, 0 + br i1 %not_err73, label %after_check74, label %voiderr75 + +after_check74: ; preds = %voiderr63 + br label %voiderr75 + +voiderr75: ; preds = %after_check74, %voiderr63 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.11, i32 0, i32 0), i64 2 }, %"char[]"* %taddr77, align 8 + %103 = bitcast %"char[]"* %taddr77 to { i8*, i64 }* + %104 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %103, i32 0, i32 0 + %lo78 = load i8*, i8** %104, align 8 + %105 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %103, i32 0, i32 1 + %hi79 = load i64, i64* %105, align 8 + store [13 x i8]* bitcast ([14 x i8]* @.str.12 to [13 x i8]*), [13 x i8]** %taddr82, align 8 + %106 = bitcast [13 x i8]** %taddr82 to i8* + %107 = insertvalue %variant undef, i8* %106, 0 + %108 = insertvalue %variant %107, i64 ptrtoint (%.introspect* @"ct$p$a13$char" to i64), 1 + %109 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots81, i64 0, i64 0 + store %variant %108, %variant* %109, align 16 + %110 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg80, i32 0, i32 1 + store i64 1, i64* %110, align 8 + %111 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg80, i32 0, i32 0 + %112 = bitcast [1 x %variant]* %varargslots81 to %variant* + store %variant* %112, %variant** %111, align 8 + %113 = bitcast %"variant[]"* %vararg80 to { i8*, i64 }* + %114 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %113, i32 0, i32 0 + %lo83 = load i8*, i8** %114, align 8 + %115 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %113, i32 0, i32 1 + %hi84 = load i64, i64* %115, align 8 + %116 = call i64 @std_io_printfln(i64* %retparam76, i8* %lo78, i64 %hi79, i8* %lo83, i64 %hi84) + %not_err85 = icmp eq i64 %116, 0 + br i1 %not_err85, label %after_check86, label %voiderr87 + +after_check86: ; preds = %voiderr75 + br label %voiderr87 + +voiderr87: ; preds = %after_check86, %voiderr75 + store i32 (i32)* @test_test2, i32 (i32)** %y, align 8 + store i64 ptrtoint (%.introspect* @"ct$p$fn$int$int$" to i64), i64* %zfoke, align 8 + ret void +} diff --git a/test/test_suite/functions/naked_function.c3t b/test/test_suite/functions/naked_function.c3t index 86580849e..55830a596 100644 --- a/test/test_suite/functions/naked_function.c3t +++ b/test/test_suite/functions/naked_function.c3t @@ -5,7 +5,7 @@ fn void test(int i) @naked } -// #expect: naked_function.ll +/* #expect: naked_function.ll define void @naked_function_test(i32 %0) #0 { entry: diff --git a/test/test_suite/functions/too_many_params.c3 b/test/test_suite/functions/too_many_params.c3 new file mode 100644 index 000000000..1c63bfe6a --- /dev/null +++ b/test/test_suite/functions/too_many_params.c3 @@ -0,0 +1,30 @@ +import std::io; +define Tester = fn int(int x, int y, int z); + +fn int test1( + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 20 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. To accept more arguments, consider using varargs + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 200 +) { return 1; } + +fn int test2( + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 20 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200 + int... x +) { return 1; } + diff --git a/test/test_suite/statements/default_args.c3 b/test/test_suite/statements/default_args.c3 index 86005a917..2c9aaa347 100644 --- a/test/test_suite/statements/default_args.c3 +++ b/test/test_suite/statements/default_args.c3 @@ -1,2 +1,4 @@ -define Foo = fn void(int a = 10); // #error: Function types may not have default arguments. +define Foo = fn void(int a = 10); +fn int abc() { return 1; } +define Foo2 = fn void(int a = abc()); diff --git a/test/test_suite2/functions/func_ptr_conversions_and_names.c3t b/test/test_suite2/functions/func_ptr_conversions_and_names.c3t new file mode 100644 index 000000000..ba5a13ad9 --- /dev/null +++ b/test/test_suite2/functions/func_ptr_conversions_and_names.c3t @@ -0,0 +1,325 @@ +// #target: macos-x64 +module test; +import std::io; +define Func = fn int(int y); +define FuncOther = fn bool(char*); +define FuncSame = fn int(int z = 444); + +fn int test(int a) { return a; } +fn int test2(int b = 3) { return b; } + +fn int! test3(int b = 3) { return b; } +fn int! test4(int b = 3) { return b; } + +fn void main() +{ + Func a = &test; + Func b = &test2; + io::printfln("%d", a(.y = 123)); + io::printfln("%d", (&test2)()); + FuncSame z = &test2; + io::printfln("%d", z()); + io::printfln("%s", $qnameof($typeof(b ? &test2 : &test))); + io::printfln("%s", $nameof($typeof(b ? &test2 : &test))); + io::printfln("%s", $qnameof($typeof(&test2))); + io::printfln("%s", $nameof($typeof(&test2))); + io::printfln("%s", $nameof($typeof(b ? &test4 : &test3))); + + $typeof(b ? &test2 : &test) y = &test2; + typeid zfoke = $typeof(y).typeid; +} + + +/* #expect: test.ll + +@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@"ct$int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@.str.2 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 +@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.4 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1 +@"ct$char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$a12$char" = linkonce constant %.introspect { i8 15, i64 12, i64 ptrtoint (ptr @"ct$char" to i64), i64 12, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a12$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"ct$a12$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.5 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.6 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1 +@.str.7 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.8 = private unnamed_addr constant [13 x i8] c"test::test2*\00", align 1 +@.str.9 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.10 = private unnamed_addr constant [7 x i8] c"test2*\00", align 1 +@"ct$a6$char" = linkonce constant %.introspect { i8 15, i64 6, i64 ptrtoint (ptr @"ct$char" to i64), i64 6, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a6$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"ct$a6$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 +@.str.12 = private unnamed_addr constant [14 x i8] c"fn int!(int)*\00", align 1 +@"ct$a13$char" = linkonce constant %.introspect { i8 15, i64 13, i64 ptrtoint (ptr @"ct$char" to i64), i64 13, [0 x i64] zeroinitializer }, align 8 +@"ct$p$a13$char" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"ct$a13$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$fn$int$int$" = linkonce constant %.introspect { i8 13, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"ct$p$fn$int$int$" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"ct$fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 + +define void @test_main() #0 { +entry: + %a = alloca ptr, align 8 + %b = alloca ptr, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %taddr1 = alloca i32, align 4 + %retparam4 = alloca i64, align 8 + %taddr5 = alloca %"char[]", align 8 + %vararg8 = alloca %"variant[]", align 8 + %varargslots9 = alloca [1 x %variant], align 16 + %taddr10 = alloca i32, align 4 + %z = alloca ptr, align 8 + %retparam16 = alloca i64, align 8 + %taddr17 = alloca %"char[]", align 8 + %vararg20 = alloca %"variant[]", align 8 + %varargslots21 = alloca [1 x %variant], align 16 + %taddr22 = alloca i32, align 4 + %retparam28 = alloca i64, align 8 + %taddr29 = alloca %"char[]", align 8 + %vararg32 = alloca %"variant[]", align 8 + %varargslots33 = alloca [1 x %variant], align 16 + %taddr34 = alloca ptr, align 8 + %retparam40 = alloca i64, align 8 + %taddr41 = alloca %"char[]", align 8 + %vararg44 = alloca %"variant[]", align 8 + %varargslots45 = alloca [1 x %variant], align 16 + %taddr46 = alloca ptr, align 8 + %retparam52 = alloca i64, align 8 + %taddr53 = alloca %"char[]", align 8 + %vararg56 = alloca %"variant[]", align 8 + %varargslots57 = alloca [1 x %variant], align 16 + %taddr58 = alloca ptr, align 8 + %retparam64 = alloca i64, align 8 + %taddr65 = alloca %"char[]", align 8 + %vararg68 = alloca %"variant[]", align 8 + %varargslots69 = alloca [1 x %variant], align 16 + %taddr70 = alloca ptr, align 8 + %retparam76 = alloca i64, align 8 + %taddr77 = alloca %"char[]", align 8 + %vararg80 = alloca %"variant[]", align 8 + %varargslots81 = alloca [1 x %variant], align 16 + %taddr82 = alloca ptr, align 8 + %y = alloca ptr, align 8 + %zfoke = alloca i64, align 8 + store ptr @test_test, ptr %a, align 8 + store ptr @test_test2, ptr %b, align 8 + store %"char[]" { ptr @.str, i64 2 }, ptr %taddr, align 8 + %0 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0 + %lo = load ptr, ptr %0, align 8 + %1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1 + %hi = load i64, ptr %1, align 8 + %2 = load ptr, ptr %a, align 8 + %3 = call i32 %2(i32 123) + store i32 %3, ptr %taddr1, align 4 + %4 = insertvalue %variant undef, ptr %taddr1, 0 + %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 + store %variant %5, ptr %6, align 16 + %7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1 + store i64 1, ptr %7, align 8 + %8 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0 + store ptr %varargslots, ptr %8, align 8 + %9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0 + %lo2 = load ptr, ptr %9, align 8 + %10 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1 + %hi3 = load i64, ptr %10, align 8 + %11 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3) + %not_err = icmp eq i64 %11, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + store %"char[]" { ptr @.str.1, i64 2 }, ptr %taddr5, align 8 + %12 = getelementptr inbounds { ptr, i64 }, ptr %taddr5, i32 0, i32 0 + %lo6 = load ptr, ptr %12, align 8 + %13 = getelementptr inbounds { ptr, i64 }, ptr %taddr5, i32 0, i32 1 + %hi7 = load i64, ptr %13, align 8 + %14 = call i32 @test_test2(i32 3) + store i32 %14, ptr %taddr10, align 4 + %15 = insertvalue %variant undef, ptr %taddr10, 0 + %16 = insertvalue %variant %15, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %17 = getelementptr inbounds [1 x %variant], ptr %varargslots9, i64 0, i64 0 + store %variant %16, ptr %17, align 16 + %18 = getelementptr inbounds %"variant[]", ptr %vararg8, i32 0, i32 1 + store i64 1, ptr %18, align 8 + %19 = getelementptr inbounds %"variant[]", ptr %vararg8, i32 0, i32 0 + store ptr %varargslots9, ptr %19, align 8 + %20 = getelementptr inbounds { ptr, i64 }, ptr %vararg8, i32 0, i32 0 + %lo11 = load ptr, ptr %20, align 8 + %21 = getelementptr inbounds { ptr, i64 }, ptr %vararg8, i32 0, i32 1 + %hi12 = load i64, ptr %21, align 8 + %22 = call i64 @std_io_printfln(ptr %retparam4, ptr %lo6, i64 %hi7, ptr %lo11, i64 %hi12) + %not_err13 = icmp eq i64 %22, 0 + br i1 %not_err13, label %after_check14, label %voiderr15 + +after_check14: ; preds = %voiderr + br label %voiderr15 + +voiderr15: ; preds = %after_check14, %voiderr + store ptr @test_test2, ptr %z, align 8 + store %"char[]" { ptr @.str.2, i64 2 }, ptr %taddr17, align 8 + %23 = getelementptr inbounds { ptr, i64 }, ptr %taddr17, i32 0, i32 0 + %lo18 = load ptr, ptr %23, align 8 + %24 = getelementptr inbounds { ptr, i64 }, ptr %taddr17, i32 0, i32 1 + %hi19 = load i64, ptr %24, align 8 + %25 = load ptr, ptr %z, align 8 + %26 = call i32 %25(i32 444) + store i32 %26, ptr %taddr22, align 4 + %27 = insertvalue %variant undef, ptr %taddr22, 0 + %28 = insertvalue %variant %27, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %29 = getelementptr inbounds [1 x %variant], ptr %varargslots21, i64 0, i64 0 + store %variant %28, ptr %29, align 16 + %30 = getelementptr inbounds %"variant[]", ptr %vararg20, i32 0, i32 1 + store i64 1, ptr %30, align 8 + %31 = getelementptr inbounds %"variant[]", ptr %vararg20, i32 0, i32 0 + store ptr %varargslots21, ptr %31, align 8 + %32 = getelementptr inbounds { ptr, i64 }, ptr %vararg20, i32 0, i32 0 + %lo23 = load ptr, ptr %32, align 8 + %33 = getelementptr inbounds { ptr, i64 }, ptr %vararg20, i32 0, i32 1 + %hi24 = load i64, ptr %33, align 8 + %34 = call i64 @std_io_printfln(ptr %retparam16, ptr %lo18, i64 %hi19, ptr %lo23, i64 %hi24) + %not_err25 = icmp eq i64 %34, 0 + br i1 %not_err25, label %after_check26, label %voiderr27 + +after_check26: ; preds = %voiderr15 + br label %voiderr27 + +voiderr27: ; preds = %after_check26, %voiderr15 + store %"char[]" { ptr @.str.3, i64 2 }, ptr %taddr29, align 8 + %35 = getelementptr inbounds { ptr, i64 }, ptr %taddr29, i32 0, i32 0 + %lo30 = load ptr, ptr %35, align 8 + %36 = getelementptr inbounds { ptr, i64 }, ptr %taddr29, i32 0, i32 1 + %hi31 = load i64, ptr %36, align 8 + store ptr @.str.4, ptr %taddr34, align 8 + %37 = insertvalue %variant undef, ptr %taddr34, 0 + %38 = insertvalue %variant %37, i64 ptrtoint (ptr @"ct$p$a12$char" to i64), 1 + %39 = getelementptr inbounds [1 x %variant], ptr %varargslots33, i64 0, i64 0 + store %variant %38, ptr %39, align 16 + %40 = getelementptr inbounds %"variant[]", ptr %vararg32, i32 0, i32 1 + store i64 1, ptr %40, align 8 + %41 = getelementptr inbounds %"variant[]", ptr %vararg32, i32 0, i32 0 + store ptr %varargslots33, ptr %41, align 8 + %42 = getelementptr inbounds { ptr, i64 }, ptr %vararg32, i32 0, i32 0 + %lo35 = load ptr, ptr %42, align 8 + %43 = getelementptr inbounds { ptr, i64 }, ptr %vararg32, i32 0, i32 1 + %hi36 = load i64, ptr %43, align 8 + %44 = call i64 @std_io_printfln(ptr %retparam28, ptr %lo30, i64 %hi31, ptr %lo35, i64 %hi36) + %not_err37 = icmp eq i64 %44, 0 + br i1 %not_err37, label %after_check38, label %voiderr39 + +after_check38: ; preds = %voiderr27 + br label %voiderr39 + +voiderr39: ; preds = %after_check38, %voiderr27 + store %"char[]" { ptr @.str.5, i64 2 }, ptr %taddr41, align 8 + %45 = getelementptr inbounds { ptr, i64 }, ptr %taddr41, i32 0, i32 0 + %lo42 = load ptr, ptr %45, align 8 + %46 = getelementptr inbounds { ptr, i64 }, ptr %taddr41, i32 0, i32 1 + %hi43 = load i64, ptr %46, align 8 + store ptr @.str.6, ptr %taddr46, align 8 + %47 = insertvalue %variant undef, ptr %taddr46, 0 + %48 = insertvalue %variant %47, i64 ptrtoint (ptr @"ct$p$a12$char" to i64), 1 + %49 = getelementptr inbounds [1 x %variant], ptr %varargslots45, i64 0, i64 0 + store %variant %48, ptr %49, align 16 + %50 = getelementptr inbounds %"variant[]", ptr %vararg44, i32 0, i32 1 + store i64 1, ptr %50, align 8 + %51 = getelementptr inbounds %"variant[]", ptr %vararg44, i32 0, i32 0 + store ptr %varargslots45, ptr %51, align 8 + %52 = getelementptr inbounds { ptr, i64 }, ptr %vararg44, i32 0, i32 0 + %lo47 = load ptr, ptr %52, align 8 + %53 = getelementptr inbounds { ptr, i64 }, ptr %vararg44, i32 0, i32 1 + %hi48 = load i64, ptr %53, align 8 + %54 = call i64 @std_io_printfln(ptr %retparam40, ptr %lo42, i64 %hi43, ptr %lo47, i64 %hi48) + %not_err49 = icmp eq i64 %54, 0 + br i1 %not_err49, label %after_check50, label %voiderr51 + +after_check50: ; preds = %voiderr39 + br label %voiderr51 + +voiderr51: ; preds = %after_check50, %voiderr39 + store %"char[]" { ptr @.str.7, i64 2 }, ptr %taddr53, align 8 + %55 = getelementptr inbounds { ptr, i64 }, ptr %taddr53, i32 0, i32 0 + %lo54 = load ptr, ptr %55, align 8 + %56 = getelementptr inbounds { ptr, i64 }, ptr %taddr53, i32 0, i32 1 + %hi55 = load i64, ptr %56, align 8 + store ptr @.str.8, ptr %taddr58, align 8 + %57 = insertvalue %variant undef, ptr %taddr58, 0 + %58 = insertvalue %variant %57, i64 ptrtoint (ptr @"ct$p$a12$char" to i64), 1 + %59 = getelementptr inbounds [1 x %variant], ptr %varargslots57, i64 0, i64 0 + store %variant %58, ptr %59, align 16 + %60 = getelementptr inbounds %"variant[]", ptr %vararg56, i32 0, i32 1 + store i64 1, ptr %60, align 8 + %61 = getelementptr inbounds %"variant[]", ptr %vararg56, i32 0, i32 0 + store ptr %varargslots57, ptr %61, align 8 + %62 = getelementptr inbounds { ptr, i64 }, ptr %vararg56, i32 0, i32 0 + %lo59 = load ptr, ptr %62, align 8 + %63 = getelementptr inbounds { ptr, i64 }, ptr %vararg56, i32 0, i32 1 + %hi60 = load i64, ptr %63, align 8 + %64 = call i64 @std_io_printfln(ptr %retparam52, ptr %lo54, i64 %hi55, ptr %lo59, i64 %hi60) + %not_err61 = icmp eq i64 %64, 0 + br i1 %not_err61, label %after_check62, label %voiderr63 + +after_check62: ; preds = %voiderr51 + br label %voiderr63 + +voiderr63: ; preds = %after_check62, %voiderr51 + store %"char[]" { ptr @.str.9, i64 2 }, ptr %taddr65, align 8 + %65 = getelementptr inbounds { ptr, i64 }, ptr %taddr65, i32 0, i32 0 + %lo66 = load ptr, ptr %65, align 8 + %66 = getelementptr inbounds { ptr, i64 }, ptr %taddr65, i32 0, i32 1 + %hi67 = load i64, ptr %66, align 8 + store ptr @.str.10, ptr %taddr70, align 8 + %67 = insertvalue %variant undef, ptr %taddr70, 0 + %68 = insertvalue %variant %67, i64 ptrtoint (ptr @"ct$p$a6$char" to i64), 1 + %69 = getelementptr inbounds [1 x %variant], ptr %varargslots69, i64 0, i64 0 + store %variant %68, ptr %69, align 16 + %70 = getelementptr inbounds %"variant[]", ptr %vararg68, i32 0, i32 1 + store i64 1, ptr %70, align 8 + %71 = getelementptr inbounds %"variant[]", ptr %vararg68, i32 0, i32 0 + store ptr %varargslots69, ptr %71, align 8 + %72 = getelementptr inbounds { ptr, i64 }, ptr %vararg68, i32 0, i32 0 + %lo71 = load ptr, ptr %72, align 8 + %73 = getelementptr inbounds { ptr, i64 }, ptr %vararg68, i32 0, i32 1 + %hi72 = load i64, ptr %73, align 8 + %74 = call i64 @std_io_printfln(ptr %retparam64, ptr %lo66, i64 %hi67, ptr %lo71, i64 %hi72) + %not_err73 = icmp eq i64 %74, 0 + br i1 %not_err73, label %after_check74, label %voiderr75 + +after_check74: ; preds = %voiderr63 + br label %voiderr75 + +voiderr75: ; preds = %after_check74, %voiderr63 + store %"char[]" { ptr @.str.11, i64 2 }, ptr %taddr77, align 8 + %75 = getelementptr inbounds { ptr, i64 }, ptr %taddr77, i32 0, i32 0 + %lo78 = load ptr, ptr %75, align 8 + %76 = getelementptr inbounds { ptr, i64 }, ptr %taddr77, i32 0, i32 1 + %hi79 = load i64, ptr %76, align 8 + store ptr @.str.12, ptr %taddr82, align 8 + %77 = insertvalue %variant undef, ptr %taddr82, 0 + %78 = insertvalue %variant %77, i64 ptrtoint (ptr @"ct$p$a13$char" to i64), 1 + %79 = getelementptr inbounds [1 x %variant], ptr %varargslots81, i64 0, i64 0 + store %variant %78, ptr %79, align 16 + %80 = getelementptr inbounds %"variant[]", ptr %vararg80, i32 0, i32 1 + store i64 1, ptr %80, align 8 + %81 = getelementptr inbounds %"variant[]", ptr %vararg80, i32 0, i32 0 + store ptr %varargslots81, ptr %81, align 8 + %82 = getelementptr inbounds { ptr, i64 }, ptr %vararg80, i32 0, i32 0 + %lo83 = load ptr, ptr %82, align 8 + %83 = getelementptr inbounds { ptr, i64 }, ptr %vararg80, i32 0, i32 1 + %hi84 = load i64, ptr %83, align 8 + %84 = call i64 @std_io_printfln(ptr %retparam76, ptr %lo78, i64 %hi79, ptr %lo83, i64 %hi84) + %not_err85 = icmp eq i64 %84, 0 + br i1 %not_err85, label %after_check86, label %voiderr87 + +after_check86: ; preds = %voiderr75 + br label %voiderr87 + +voiderr87: ; preds = %after_check86, %voiderr75 + store ptr @test_test2, ptr %y, align 8 + store i64 ptrtoint (ptr @"ct$p$fn$int$int$" to i64), ptr %zfoke, align 8 + ret void +} diff --git a/test/test_suite2/functions/too_many_params.c3 b/test/test_suite2/functions/too_many_params.c3 new file mode 100644 index 000000000..1c63bfe6a --- /dev/null +++ b/test/test_suite2/functions/too_many_params.c3 @@ -0,0 +1,30 @@ +import std::io; +define Tester = fn int(int x, int y, int z); + +fn int test1( + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 20 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. To accept more arguments, consider using varargs + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 200 +) { return 1; } + +fn int test2( + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 20 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200 + int... x +) { return 1; } + diff --git a/test/test_suite2/statements/default_args.c3 b/test/test_suite2/statements/default_args.c3 index 86005a917..2c9aaa347 100644 --- a/test/test_suite2/statements/default_args.c3 +++ b/test/test_suite2/statements/default_args.c3 @@ -1,2 +1,4 @@ -define Foo = fn void(int a = 10); // #error: Function types may not have default arguments. +define Foo = fn void(int a = 10); +fn int abc() { return 1; } +define Foo2 = fn void(int a = abc());