mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
5 Commits
0.4stripun
...
0.4godbolt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82c3facb65 | ||
|
|
266dba466c | ||
|
|
379a5f670f | ||
|
|
8eaad81800 | ||
|
|
4baacc7d52 |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -184,7 +184,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [16]
|
||||
llvm_version: [16, 17]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -38,6 +38,26 @@ fn void List.tinit(List* list, usz initial_capacity = 16)
|
||||
list.init(initial_capacity, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn String List.to_string(List* list, Allocator* using = mem::heap()) @dynamic
|
||||
{
|
||||
if (!list.size) return "[]".copy(using);
|
||||
if (list.size == 1) return string::printf("[%s]", list.entries[0], .using = using);
|
||||
|
||||
@stack_mem(512 + 128; Allocator* mem)
|
||||
{
|
||||
DString str;
|
||||
str.init(512, mem);
|
||||
str.append("[");
|
||||
foreach (i, element : list.entries[:list.size])
|
||||
{
|
||||
if (i != 0) str.append(", ");
|
||||
str.printf("%s", element);
|
||||
}
|
||||
str.printf("]");
|
||||
return str.copy_str(using);
|
||||
};
|
||||
}
|
||||
|
||||
fn void List.push(List* list, Type element) @inline
|
||||
{
|
||||
list.append(element);
|
||||
|
||||
@@ -135,9 +135,9 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
|
||||
this.width = old_width;
|
||||
this.prec = old_prec;
|
||||
}
|
||||
@pool()
|
||||
@stack_mem(512; Allocator* mem)
|
||||
{
|
||||
this.out_substr(arg.to_string(mem::temp()))!;
|
||||
this.out_substr(arg.to_string(mem))!;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,18 +50,18 @@ fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
|
||||
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
}
|
||||
|
||||
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
|
||||
fn String InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
|
||||
{
|
||||
if (addr.is_ipv6)
|
||||
{
|
||||
char[8 * 5 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d,
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!;
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!!;
|
||||
return res.copy(using);
|
||||
}
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!!;
|
||||
return res.copy(using);
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,10 @@ static void usage(void)
|
||||
OUTPUT(" --emit-llvm - Emit LLVM IR as a .ll file per module.");
|
||||
OUTPUT(" --asm-out <dir> - Override asm output directory for '--emit-asm'.");
|
||||
OUTPUT(" --emit-asm - Emit asm as a .s file per module.");
|
||||
OUTPUT(" --obj - Emit object files. (Enabled by default)");
|
||||
OUTPUT(" --no-obj - Do not output object files, this is only valid for `compile-only`.");
|
||||
OUTPUT(" --emit-stdlib - Output files for the standard library. (Enabled by default)");
|
||||
OUTPUT(" --no-emit-stdlib - Do not output object files (nor asm or ir) for the standard library.");
|
||||
OUTPUT(" --target <target> - Compile for a particular architecture + OS target.");
|
||||
OUTPUT(" --threads <number> - Set the number of threads to use for compilation.");
|
||||
OUTPUT(" --safe - Set mode to 'safe', generating runtime traps on overflows and contract violations.");
|
||||
@@ -134,7 +138,8 @@ static void usage(void)
|
||||
OUTPUT(" --x86vec=<option> - Set max type of vector use: none, mmx, sse, avx, avx512, native.");
|
||||
OUTPUT(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
|
||||
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
|
||||
OUTPUT(" --strip-unused - Strip unused code and globals from the output (experimental)");
|
||||
OUTPUT(" --strip-unused - Strip unused code and globals from the output. (Enabled by default)");
|
||||
OUTPUT(" --no-strip-unused - Do not strip unused code and globals from the output.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --debug-stats - Print debug statistics.");
|
||||
#ifndef NDEBUG
|
||||
@@ -549,9 +554,14 @@ static void parse_option(BuildOptions *options)
|
||||
print_version();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if (match_longopt("no-strip-unused"))
|
||||
{
|
||||
options->no_strip_unused = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("strip-unused"))
|
||||
{
|
||||
options->strip_unused = true;
|
||||
options->no_strip_unused = false;
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("x86vec")))
|
||||
@@ -585,6 +595,26 @@ static void parse_option(BuildOptions *options)
|
||||
OUTPUT("C3 is low level programming language based on C.");
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if (match_longopt("no-obj"))
|
||||
{
|
||||
options->no_obj = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("obj"))
|
||||
{
|
||||
options->no_obj = false;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("no-emit-stdlib"))
|
||||
{
|
||||
options->no_emit_stdlib = true;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("emit-stdlib"))
|
||||
{
|
||||
options->no_emit_stdlib = false;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("debug-log"))
|
||||
{
|
||||
debug_log = true;
|
||||
@@ -871,7 +901,6 @@ BuildOptions parse_arguments(int argc, const char *argv[])
|
||||
BuildOptions build_options = {
|
||||
.path = ".",
|
||||
.emit_llvm = false,
|
||||
.emit_bitcode = true,
|
||||
.optimization_setting_override = OPT_SETTING_NOT_SET,
|
||||
.debug_info_override = DEBUG_INFO_NOT_SET,
|
||||
.safe_mode = -1,
|
||||
|
||||
@@ -321,11 +321,12 @@ typedef struct BuildOptions_
|
||||
int safe_mode;
|
||||
bool emit_llvm;
|
||||
bool emit_asm;
|
||||
bool emit_bitcode;
|
||||
bool test_mode;
|
||||
bool no_stdlib;
|
||||
bool no_entry;
|
||||
bool no_libc;
|
||||
bool no_obj;
|
||||
bool no_emit_stdlib;
|
||||
bool force_linker;
|
||||
bool read_stdin;
|
||||
bool print_output;
|
||||
@@ -340,7 +341,7 @@ typedef struct BuildOptions_
|
||||
X86CpuSet x86_cpu_set;
|
||||
RiscvFloatCapability riscv_float_capability;
|
||||
MemoryEnvironment memory_environment;
|
||||
bool strip_unused;
|
||||
bool no_strip_unused;
|
||||
bool print_keywords;
|
||||
bool print_attributes;
|
||||
bool print_builtins;
|
||||
@@ -414,7 +415,7 @@ typedef struct
|
||||
bool emit_asm;
|
||||
bool no_stdlib;
|
||||
bool no_libc;
|
||||
bool strip_unused;
|
||||
bool no_strip_unused;
|
||||
bool emit_object_files;
|
||||
bool force_linker;
|
||||
bool benchmarking;
|
||||
@@ -422,6 +423,7 @@ typedef struct
|
||||
bool read_stdin;
|
||||
bool print_output;
|
||||
bool no_entry;
|
||||
bool no_emit_stdlib;
|
||||
int build_threads;
|
||||
OptimizationLevel optimization_level;
|
||||
MemoryEnvironment memory_environment;
|
||||
|
||||
@@ -199,7 +199,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
{
|
||||
target->feature.safe_mode = options->safe_mode == 1;
|
||||
}
|
||||
if (options->strip_unused) target->strip_unused = true;
|
||||
if (options->no_strip_unused || options->test_mode) target->no_strip_unused = true;
|
||||
|
||||
if (options->memory_environment != MEMORY_ENV_NOT_SET)
|
||||
{
|
||||
@@ -302,6 +302,11 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
target->emit_asm = false;
|
||||
target->emit_object_files = false;
|
||||
}
|
||||
if (options->no_obj)
|
||||
{
|
||||
target->emit_object_files = false;
|
||||
}
|
||||
target->no_emit_stdlib = options->no_emit_stdlib;
|
||||
for (int i = 0; i < options->lib_dir_count; i++)
|
||||
{
|
||||
vec_add(target->libdirs, options->lib_dir[i]);
|
||||
|
||||
@@ -484,21 +484,29 @@ void compiler_compile(void)
|
||||
printf("Program finished with exit code %d.\n", ret);
|
||||
}
|
||||
}
|
||||
if (output_static)
|
||||
else if (output_static)
|
||||
{
|
||||
if (!static_lib_linker(output_static, obj_files, output_file_count))
|
||||
{
|
||||
error_exit("Failed to produce static library '%s'.", output_static);
|
||||
}
|
||||
compiler_link_time = bench_mark();
|
||||
compiler_print_bench();
|
||||
printf("Static library '%s' created.", output_static);
|
||||
}
|
||||
if (output_dynamic)
|
||||
else if (output_dynamic)
|
||||
{
|
||||
if (!dynamic_lib_linker(output_dynamic, obj_files, output_file_count))
|
||||
{
|
||||
error_exit("Failed to produce static library '%s'.", output_dynamic);
|
||||
}
|
||||
printf("Dynamic library '%s' created.", output_dynamic);
|
||||
compiler_link_time = bench_mark();
|
||||
compiler_print_bench();
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler_print_bench();
|
||||
}
|
||||
free(obj_files);
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
|
||||
}
|
||||
add_arg("-arch");
|
||||
add_arg(arch_to_linker_arch(platform_target.arch));
|
||||
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
{
|
||||
add_arg("-no_exported_symbols");
|
||||
add_arg("-dead_strip");
|
||||
@@ -398,9 +398,9 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
|
||||
const char *crt_begin_dir = find_linux_crt_begin();
|
||||
const char *crt_dir = find_linux_crt();
|
||||
|
||||
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
{
|
||||
add_arg("-dead_strip");
|
||||
add_arg("--gc-sections");
|
||||
}
|
||||
|
||||
if (!crt_begin_dir || !crt_dir)
|
||||
@@ -448,9 +448,9 @@ static void linker_setup_freebsd(const char ***args_ref, LinkerType linker_type)
|
||||
{
|
||||
error_exit("Failed to find the C runtime at link time.");
|
||||
}
|
||||
if (active_target.strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
if (!active_target.no_strip_unused && active_target.type == TARGET_TYPE_EXECUTABLE)
|
||||
{
|
||||
add_arg("-dead_strip");
|
||||
add_arg("--gc-sections");
|
||||
}
|
||||
|
||||
if (is_pie_pic(platform_target.reloc_model))
|
||||
|
||||
@@ -1265,9 +1265,21 @@ LLVMMetadataRef llvm_get_debug_file(GenContext *c, FileId file_id)
|
||||
return file;
|
||||
}
|
||||
|
||||
static bool module_is_stdlib(Module *module)
|
||||
{
|
||||
if (module->name->len < 3) return false;
|
||||
if (module->name->len == 3 && strcmp(module->name->module, "std") == 0) return true;
|
||||
if (module->name->len > 5 && memcmp(module->name->module, "std::", 5) == 0) return true;
|
||||
if (module->name->len == 4 && strcmp(module->name->module, "libc") == 0) return true;
|
||||
if (module->name->len > 6 && memcmp(module->name->module, "libc::", 6) == 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context)
|
||||
{
|
||||
if (!vec_size(module->units)) return NULL;
|
||||
if (active_target.no_emit_stdlib && module_is_stdlib(module)) return NULL;
|
||||
|
||||
assert(intrinsics_setup);
|
||||
|
||||
bool has_elements = false;
|
||||
@@ -1275,7 +1287,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
gencontext_init(gen_context, module, shared_context);
|
||||
gencontext_begin_module(gen_context);
|
||||
|
||||
bool only_used = active_target.strip_unused && !active_target.testing;
|
||||
bool only_used = !active_target.no_strip_unused;
|
||||
|
||||
FOREACH_BEGIN(CompilationUnit *unit, module->units)
|
||||
|
||||
@@ -1296,10 +1308,12 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *type_decl, unit->types)
|
||||
if (only_used && !type_decl->is_live) continue;
|
||||
llvm_emit_type_decls(gen_context, type_decl);
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *enum_decl, unit->enums)
|
||||
if (only_used && !enum_decl->is_live) continue;
|
||||
llvm_emit_type_decls(gen_context, enum_decl);
|
||||
FOREACH_END();
|
||||
|
||||
@@ -1384,8 +1398,6 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
|
||||
llvm_emit_constructors_and_destructors(gen_context);
|
||||
|
||||
// EmitDeferred()
|
||||
|
||||
if (llvm_use_debug(gen_context))
|
||||
{
|
||||
LLVMDIBuilderFinalize(gen_context->debug.builder);
|
||||
|
||||
@@ -2332,6 +2332,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
return false;
|
||||
}
|
||||
global_context.test_func = decl;
|
||||
if (active_target.testing) decl->no_strip = true;
|
||||
}
|
||||
bool is_test = decl->func_decl.attr_test;
|
||||
Signature *sig = &decl->func_decl.signature;
|
||||
|
||||
@@ -178,12 +178,14 @@ static void sema_trace_stmt_liveness(Ast *ast)
|
||||
|
||||
static void sema_trace_const_initializer_liveness(ConstInitializer *const_init)
|
||||
{
|
||||
RETRY:
|
||||
switch (const_init->kind)
|
||||
{
|
||||
case CONST_INIT_ZERO:
|
||||
return;
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
UNREACHABLE
|
||||
const_init = const_init->init_array_value.element;
|
||||
goto RETRY;
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
bool was_modified = false;
|
||||
@@ -204,8 +206,8 @@ static void sema_trace_const_initializer_liveness(ConstInitializer *const_init)
|
||||
return;
|
||||
}
|
||||
case CONST_INIT_UNION:
|
||||
sema_trace_const_initializer_liveness(const_init->init_union.element);
|
||||
return;
|
||||
const_init = const_init->init_union.element;
|
||||
goto RETRY;
|
||||
case CONST_INIT_STRUCT:
|
||||
{
|
||||
Decl *decl = const_init->type->decl;
|
||||
@@ -353,8 +355,16 @@ RETRY:
|
||||
sema_trace_expr_list_liveness(expr->designated_init_list);
|
||||
return;
|
||||
case EXPR_EXPR_BLOCK:
|
||||
sema_trace_stmt_liveness(astptr(expr->expr_block.first_stmt));
|
||||
{
|
||||
AstId current = expr->expr_block.first_stmt;
|
||||
if (!current) return;
|
||||
do
|
||||
{
|
||||
Ast *value = ast_next(¤t);
|
||||
sema_trace_stmt_liveness(value);
|
||||
} while (current);
|
||||
return;
|
||||
}
|
||||
case EXPR_IDENTIFIER:
|
||||
sema_trace_decl_liveness(expr->identifier_expr.decl);
|
||||
return;
|
||||
@@ -452,10 +462,15 @@ void sema_trace_liveness(void)
|
||||
{
|
||||
sema_trace_decl_liveness(global_context.main);
|
||||
}
|
||||
bool keep_tests = active_target.testing;
|
||||
FOREACH_BEGIN(Decl *function, global_context.method_extensions)
|
||||
if (function->func_decl.attr_dynamic) function->no_strip = true;
|
||||
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Module *module, global_context.module_list)
|
||||
FOREACH_BEGIN(CompilationUnit *unit, module->units)
|
||||
FOREACH_BEGIN(Decl *function, unit->functions)
|
||||
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
|
||||
if (function->is_export || function->no_strip || (function->func_decl.attr_test && keep_tests)) sema_trace_decl_liveness(function);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *method, unit->methods)
|
||||
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
|
||||
@@ -463,26 +478,67 @@ void sema_trace_liveness(void)
|
||||
FOREACH_BEGIN(Decl *var, unit->vars)
|
||||
if (var->is_export || var->no_strip) sema_trace_decl_liveness(var);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *method, unit->local_method_extensions)
|
||||
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *xxlizer, unit->xxlizers)
|
||||
sema_trace_decl_liveness(xxlizer);
|
||||
FOREACH_END();
|
||||
FOREACH_END();
|
||||
FOREACH_END();
|
||||
}
|
||||
|
||||
INLINE void sema_trace_type_liveness(Type *type)
|
||||
{
|
||||
if (!type || !type_is_user_defined(type)) return;
|
||||
sema_trace_decl_liveness(type->decl);
|
||||
}
|
||||
|
||||
INLINE void sema_trace_decl_dynamic_methods(Decl *decl)
|
||||
{
|
||||
Decl **methods = decl->methods;
|
||||
unsigned method_count = vec_size(methods);
|
||||
if (!method_count) return;
|
||||
for (unsigned i = 0; i < method_count; i++)
|
||||
{
|
||||
Decl *method = methods[i];
|
||||
if (!method->func_decl.attr_dynamic) continue;
|
||||
sema_trace_decl_liveness(method);
|
||||
}
|
||||
}
|
||||
|
||||
static void sema_trace_decl_liveness(Decl *decl)
|
||||
{
|
||||
RETRY:
|
||||
if (!decl || decl->is_live) return;
|
||||
decl->is_live = true;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
if (!decl->typedef_decl.is_func)
|
||||
{
|
||||
sema_trace_type_liveness(decl->typedef_decl.type_info->type);
|
||||
return;
|
||||
}
|
||||
FOREACH_BEGIN(Decl *param, decl->typedef_decl.function_signature.params)
|
||||
sema_trace_decl_liveness(param);
|
||||
FOREACH_END();
|
||||
sema_trace_type_liveness(typeinfotype(decl->typedef_decl.function_signature.rtype));
|
||||
return;
|
||||
case DECL_DEFINE:
|
||||
decl = decl->define_decl.alias;
|
||||
goto RETRY;
|
||||
case DECL_DISTINCT:
|
||||
case DECL_ENUM:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_FAULT:
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
sema_trace_decl_dynamic_methods(decl);
|
||||
return;
|
||||
case DECL_POISONED:
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_FAULTVALUE:
|
||||
return;
|
||||
case DECL_CT_CASE:
|
||||
@@ -508,20 +564,27 @@ static void sema_trace_decl_liveness(Decl *decl)
|
||||
{
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return;
|
||||
break;
|
||||
case VARDECL_PARAM_EXPR:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_REF:
|
||||
case VARDECL_PARAM:
|
||||
sema_trace_type_liveness(decl->type);
|
||||
if (decl->var.init_expr && decl->var.init_expr->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
sema_trace_expr_liveness(decl->var.init_expr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sema_trace_type_liveness(decl->type);
|
||||
sema_trace_expr_liveness(decl->var.init_expr);
|
||||
break;
|
||||
}
|
||||
sema_trace_expr_liveness(decl->var.init_expr);
|
||||
return;
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
sema_trace_stmt_liveness(astptrzero(decl->xxlizer.init));
|
||||
return;
|
||||
case DECL_STRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_UNION:
|
||||
return;
|
||||
case DECL_DECLARRAY:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -2927,6 +2927,49 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
|
||||
func->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Signature any_sig = any->func_decl.signature;
|
||||
Signature this_sig = func->func_decl.signature;
|
||||
Type *any_rtype = typeinfotype(any_sig.rtype);
|
||||
Type *this_rtype = typeinfotype(this_sig.rtype);
|
||||
if (any_rtype->canonical != this_rtype->canonical)
|
||||
{
|
||||
SEMA_ERROR(type_infoptr(this_sig.rtype), "The prototype method has a return type %s, but this function returns %s, they need to match.",
|
||||
type_quoted_error_string(any_rtype), type_quoted_error_string(this_rtype));
|
||||
SEMA_NOTE(type_infoptr(any_sig.rtype), "The interface definition is here.");
|
||||
return false;
|
||||
}
|
||||
Decl **any_params = any_sig.params;
|
||||
Decl **this_params = this_sig.params;
|
||||
unsigned any_param_count = vec_size(any_params);
|
||||
unsigned this_param_count = vec_size(this_params);
|
||||
if (any_param_count != this_param_count)
|
||||
{
|
||||
if (any_param_count > this_param_count)
|
||||
{
|
||||
SEMA_ERROR(func, "This function is missing parameters, %d parameters were expected.", any_param_count);
|
||||
SEMA_NOTE(any_params[this_param_count], "Compare with the interface definition.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(this_params[any_param_count], "This function has too many parameters (%d).", this_param_count);
|
||||
SEMA_NOTE(any, "Compare with the interface, which has only %d parameter%s.",
|
||||
any_param_count, any_param_count == 1 ? "" : "s");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FOREACH_BEGIN_IDX(i, Decl *param, this_params)
|
||||
if (i == 0) continue;
|
||||
if (param->type->canonical != any_params[i]->type->canonical)
|
||||
{
|
||||
SEMA_ERROR(param->var.type_info, "The prototype argument has type %s, but in this function it has type %s. Please make them match.",
|
||||
type_quoted_error_string(any_params[i]->type), type_quoted_error_string(param->type));
|
||||
SEMA_NOTE(any_params[i]->var.type_info, "The interface definition is here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FOREACH_END();
|
||||
func->func_decl.any_prototype = declid(any);
|
||||
}
|
||||
Signature *signature = &func->func_decl.signature;
|
||||
|
||||
@@ -373,12 +373,13 @@ RESOLVE_LAMBDA:;
|
||||
if (found_lambda) goto RESOLVE_LAMBDA;
|
||||
halt_on_error();
|
||||
|
||||
if (active_target.strip_unused && !active_target.testing)
|
||||
assign_panicfn();
|
||||
|
||||
if (!active_target.no_strip_unused)
|
||||
{
|
||||
sema_trace_liveness();
|
||||
}
|
||||
|
||||
assign_panicfn();
|
||||
|
||||
compiler_sema_time = bench_mark();
|
||||
|
||||
|
||||
@@ -25,6 +25,15 @@ static void cleanup()
|
||||
|
||||
int main_real(int argc, const char *argv[])
|
||||
{
|
||||
printf("------------------------------------------------------------\n"
|
||||
" PLEASE NOTE, this version of the compiler has enabled dead\n"
|
||||
" code stripping by default. This functionality has not been\n"
|
||||
" completely audited, so if you run into any linking error, \n"
|
||||
" please use --no-strip-unused to disable the feature. \n"
|
||||
" If possible, file an error here: \n"
|
||||
" https://github.com/c3lang/c3c/issues\n"
|
||||
" Thank you!\n"
|
||||
"------------------------------------------------------------\n");
|
||||
bench_begin();
|
||||
|
||||
// Setjmp will allow us to add things like fuzzing with
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.522"
|
||||
#define COMPILER_VERSION "0.4.525"
|
||||
21
test/test_suite/dynamic/dynamic_mismatch.c3
Normal file
21
test/test_suite/dynamic/dynamic_mismatch.c3
Normal file
@@ -0,0 +1,21 @@
|
||||
fn int any.test(void* a, int ag) @interface;
|
||||
|
||||
struct Foo { int a; }
|
||||
|
||||
fn int! Foo.test(Foo* f) @dynamic { return 1; } // #error: The prototype method has a return type 'int'
|
||||
|
||||
struct Foo1 { int a; }
|
||||
|
||||
fn int Foo1.test(Foo1* f, int a) @dynamic { return 1; }
|
||||
|
||||
struct Foo2 { int a; }
|
||||
|
||||
fn int Foo2.test(Foo2* f) @dynamic { return 1; } // #error: This function is missing parameters, 2
|
||||
|
||||
struct Foo3 { int a; }
|
||||
|
||||
fn int Foo3.test(Foo3* f, double a) @dynamic { return 1; } // #error: The prototype argument has type 'int'
|
||||
|
||||
struct Foo4 { int a; }
|
||||
|
||||
fn int Foo4.test(Foo4* f, double a, int x) @dynamic { return 1; } // #error: This function has too many parameters
|
||||
@@ -12,14 +12,14 @@ fn void test_ipv4()
|
||||
fn void! test_ipv4_to_string()
|
||||
{
|
||||
InetAddress a = net::ipv4_from_str("127.0.0.1")!;
|
||||
assert(a.to_string()! == "127.0.0.1");
|
||||
assert(a.to_string() == "127.0.0.1");
|
||||
}
|
||||
|
||||
fn void! test_ipv6_to_string()
|
||||
{
|
||||
InetAddress a = net::ipv6_from_str("2001:db8::2:1")!;
|
||||
a.to_string()!;
|
||||
assert(a.to_string()! == "2001:0db8:0000:0000:0000:0000:0002:0001");
|
||||
a.to_string();
|
||||
assert(a.to_string() == "2001:0db8:0000:0000:0000:0000:0002:0001");
|
||||
assert(net::ipv6_from_str("2001:db8::1").to_string()! == "2001:0db8:0000:0000:0000:0000:0000:0001");
|
||||
assert(net::ipv6_from_str("::1").to_string()! == "0000:0000:0000:0000:0000:0000:0000:0001");
|
||||
assert(net::ipv6_from_str("2001::1").to_string()! == "2001:0000:0000:0000:0000:0000:0000:0001");
|
||||
|
||||
Reference in New Issue
Block a user