Some initial parse output. Enforce handling of optionals. Fix issue where constants were folded despite the fact that they shouldn't be. Fix bug related to return foo() where foo() returns void!. (#893)

This commit is contained in:
Christoffer Lerno
2023-07-27 22:58:41 +02:00
committed by GitHub
parent d0fa473d61
commit ada3ea08fc
23 changed files with 685 additions and 312 deletions

View File

@@ -205,17 +205,15 @@ add_executable(c3c
src/build/project_creation.c
src/compiler/ast.c
src/compiler/bigint.c
src/compiler/c_abi_internal.h
src/compiler/codegen_general.c
src/compiler/compiler.c
src/compiler/compiler.h
src/compiler/context.c
src/compiler/copying.c
src/compiler/diagnostics.c
src/compiler/dwarf.h
src/compiler/enums.h
src/compiler/float.c
src/compiler/headers.c
src/compiler/json_output.c
src/compiler/lexer.c
src/compiler/libraries.c
src/compiler/linker.c

View File

@@ -141,7 +141,7 @@ fn void Object.free(&self)
{
foreach (key : self.map.key_tlist())
{
self.map.get(key).free();
(void)self.map.get(key).free();
free(key, .using = self.allocator);
}
self.map.free();
@@ -197,7 +197,7 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
defer
{
(void)free(entry.key, .using = self.allocator);
entry.value.free();
(void)entry.value.free();
}
self.map.set(key.copy(self.map.allocator), new_object);
}

View File

@@ -41,7 +41,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
{
String filename = string::temp_from_wstring((WString)&find_data.cFileName)!;
if (filename == ".." || filename == ".") continue;
list.append(path::new(filename, using));
list.append(path::new(filename, using)!);
};
} while (win32::findNextFileW(find, &find_data));
return list;

View File

@@ -206,7 +206,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
}
start_info.hStdError = wr;
|};
|}!;
void *event_output;
void *event_error;
if (options.read_async)

View File

@@ -92,7 +92,7 @@ static void usage(void)
OUTPUT(" --symtab <value> - Sets the preferred symtab size.");
OUTPUT(" -V --version - Print version information.");
OUTPUT(" -E - Lex only.");
OUTPUT(" -P - Only parse and output the AST as S-expressions.");
OUTPUT(" -P - Only parse and output the AST as JSON.");
OUTPUT(" -C - Only lex, parse and check.");
OUTPUT(" - - Read code from standard in.");
OUTPUT(" -o <file> - Write output to <file>.");

View File

@@ -93,26 +93,6 @@ static void compiler_lex(void)
exit_compiler(COMPILER_SUCCESS_EXIT);
}
void compiler_parse(void)
{
VECEACH(global_context.sources, i)
{
bool loaded = false;
const char *error;
File *file = source_file_load(global_context.sources[i], &loaded, &error);
if (!file) error_exit(error);
if (loaded) continue;
global_context_clear_errors();
parse_file(file);
}
if (active_target.read_stdin)
{
global_context_clear_errors();
parse_stdin();
}
exit_compiler(COMPILER_SUCCESS_EXIT);
}
typedef struct CompileData_
@@ -291,6 +271,37 @@ void delete_object_files(const char **files, size_t count)
}
}
void compiler_parse(void)
{
// Cleanup any errors (could there really be one here?!)
global_context_clear_errors();
// Add the standard library
if (global_context.lib_dir && !active_target.no_stdlib)
{
file_add_wildcard_files(&global_context.sources, global_context.lib_dir, true, c3_suffix_list, 3);
}
// Load and parse all files.
bool has_error = false;
VECEACH(global_context.sources, i)
{
bool loaded = false;
const char *error;
File *file = source_file_load(global_context.sources[i], &loaded, &error);
if (!file) error_exit(error);
if (loaded) continue;
if (!parse_file(file)) has_error = true;
}
if (active_target.read_stdin)
{
if (!parse_stdin()) has_error = true;
}
if (has_error) exit_compiler(EXIT_FAILURE);
compiler_parsing_time = bench_mark();
}
void compiler_compile(void)
{
sema_analysis_run();
@@ -864,6 +875,9 @@ void compile()
{
compiler_parse();
compiler_parsing_time = bench_mark();
emit_json();
exit_compiler(COMPILER_SUCCESS_EXIT);
return;
}
compiler_compile();

View File

@@ -771,9 +771,10 @@ typedef struct
bool is_builtin : 1;
bool is_func_ref : 1;
bool attr_pure : 1;
bool result_unused : 1;
bool no_return : 1;
bool is_dynamic_dispatch : 1;
bool has_optional_arg : 1;
bool must_use : 1;
AstId body;
union
{
@@ -1014,7 +1015,9 @@ typedef struct
typedef struct
{
AstId first_stmt;
bool is_noreturn;
bool is_noreturn : 1;
bool is_must_use : 1;
bool had_optional_arg : 1;
Decl **params;
BlockExit **block_exit;
} ExprMacroBlock;
@@ -1917,7 +1920,7 @@ ARENA_DEF(type_info, TypeInfo)
INLINE Type *typeinfotype(TypeInfoId id_)
{
return type_infoptr(id_)->type;
return id_ ? type_infoptr(id_)->type : NULL;
}
bool ast_is_not_empty(Ast *ast);
@@ -2245,6 +2248,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr);
bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional);
MemberIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
bool sema_analyse_expr(SemaContext *context, Expr *expr);
bool sema_expr_check_discard(Expr *expr);
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
bool sema_analyse_decl(SemaContext *context, Decl *decl);
bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl);
@@ -2289,6 +2293,8 @@ bool sema_type_error_on_binop(Expr *expr);
File *source_file_by_id(FileId file);
File *source_file_load(const char *filename, bool *already_loaded, const char **error);
void compiler_parse(void);
void emit_json(void);
#define RANGE_EXTEND_PREV(x) do { (x)->span = extend_span_with_token((x)->span, c->prev_span); } while (0)
@@ -2548,6 +2554,7 @@ INLINE bool type_is_wildcard(Type *type)
INLINE bool type_is_optional(Type *type)
{
if (!type) return false;
DECL_TYPE_KIND_REAL(kind, type);
return kind == TYPE_OPTIONAL;
}

275
src/compiler/json_output.c Normal file
View File

@@ -0,0 +1,275 @@
#include "compiler_internal.h"
#define FOREACH_DECL(a__, modules__) \
unsigned module_count_ = vec_size(modules__); \
for (unsigned i_ = 0; i_ < module_count_; i_++) { \
Module *module = modules__[i_]; \
unsigned unit_count_ = vec_size(module->units); \
for (unsigned j_ = 0; j_ < unit_count_; j_++) { \
CompilationUnit *unit = module->units[j_]; \
unsigned decl_count_ = vec_size(unit->global_decls); \
for (unsigned k_ = 0; k_ < decl_count_; k_++) { \
a__ = unit->global_decls[k_];
#define FOREACH_DECL_END } } }
#define INERT_COMMA do { if (first) { first = false; } else { fputs(",\n", file); } } while(0)
static inline void emit_modules(FILE *file)
{
fputs("\t\"modules\": {\n", file);
FOREACH_BEGIN_IDX(i, Module *module, global_context.module_list)
if (i != 0) fputs(",\n", file);
fprintf(file, "\t\t\"%s\"", module->name->module);
FOREACH_END();
fputs("\n\t},\n", file);
fputs("\t\"generic_modules\": {\n", file);
FOREACH_BEGIN_IDX(i, Module *module, global_context.generic_module_list)
if (i != 0) fputs(",\n", file);
fprintf(file, "\t\t\"%s\"", module->name->module);
FOREACH_END();
fputs("\n\t}\n", file);
}
static inline const char *decl_type_to_string(Decl *type)
{
switch (type->decl_kind)
{
case DECL_ATTRIBUTE: return "attribute";
case DECL_BITSTRUCT: return "bitstruct";
case DECL_CT_ASSERT: return "$assert";
case DECL_CT_ECHO: return "$echo";
case DECL_DEFINE: return "def";
case DECL_DISTINCT: return "distinct";
case DECL_ENUM: return "enum";
case DECL_ENUM_CONSTANT: return "enum_const";
case DECL_FAULT: return "fault";
case DECL_FAULTVALUE: return "fault_val";
case DECL_FUNC: return "function";
case DECL_FNTYPE: return "fntype";
case DECL_GLOBALS: return "global";
case DECL_INITIALIZE: return "initializer";
case DECL_FINALIZE: return "finalizer";
case DECL_IMPORT: return "import";
case DECL_CT_INCLUDE: return "$include";
case DECL_MACRO: return "macro";
case DECL_STRUCT: return "struct";
case DECL_TYPEDEF: return "typedef";
case DECL_UNION: return "union";
case DECL_VAR:
case DECL_LABEL:
case DECL_DECLARRAY:
case DECL_BODYPARAM:
case DECL_POISONED:
case DECL_ERASED:
UNREACHABLE
}
UNREACHABLE
}
static inline void emit_type_data(FILE *file, Module *module, Decl *type)
{
fprintf(file, "\t\t\"%s::%s\": {\n", module->name->module, type->name);
fprintf(file, "\t\t\t\"kind\": \"%s\"", decl_type_to_string(type));
if (type->decl_kind == DECL_STRUCT || type->decl_kind == DECL_UNION)
{
fputs(",\n\t\t\t\"members\": {\n", file);
FOREACH_BEGIN_IDX(i, Decl *member, type->strukt.members)
if (i != 0) fputs(",\n", file);
fprintf(file, "\t\t\t\t\"%s\"", member->name);
FOREACH_END();
fputs("\n\t\t\t}", file);
}
fputs("\n\t\t}", file);
}
void print_type(FILE *file, TypeInfo *type)
{
if (type->resolve_status == RESOLVE_DONE)
{
fputs(type->type->name, file);
return;
}
switch (type->kind)
{
case TYPE_INFO_POISON:
UNREACHABLE;
case TYPE_INFO_IDENTIFIER:
case TYPE_INFO_CT_IDENTIFIER:
if (type->unresolved.path)
{
fprintf(file, "%s::", type->unresolved.path->module);
}
fputs(type->unresolved.name, file);
break;
case TYPE_INFO_TYPEOF:
scratch_buffer_clear();
span_to_scratch(type->unresolved_type_expr->span);
fprintf(file, "$typeof(%s)", scratch_buffer_to_string());
break;
case TYPE_INFO_VATYPE:
fprintf(file, "$vatype(...)");
break;
case TYPE_INFO_EVALTYPE:
fprintf(file, "$evaltype(...)");
break;
case TYPE_INFO_TYPEFROM:
fprintf(file, "$typefrom(...)");
break;
case TYPE_INFO_ARRAY:
print_type(file, type->array.base);
scratch_buffer_clear();
span_to_scratch(type->array.len->span);
fprintf(file, "[%s]", scratch_buffer_to_string());
break;
case TYPE_INFO_VECTOR:
print_type(file, type->array.base);
scratch_buffer_clear();
span_to_scratch(type->array.len->span);
fprintf(file, "[<%s>]", scratch_buffer_to_string());
break;
case TYPE_INFO_INFERRED_ARRAY:
print_type(file, type->array.base);
fputs("[*]", file);
break;
case TYPE_INFO_INFERRED_VECTOR:
print_type(file, type->array.base);
fputs("[<>]", file);
break;
case TYPE_INFO_SUBARRAY:
print_type(file, type->array.base);
fputs("[]", file);
break;
case TYPE_INFO_POINTER:
print_type(file, type->array.base);
fputs("*", file);
break;
case TYPE_INFO_GENERIC:
print_type(file, type->array.base);
fputs("(<...>)", file);
break;
}
switch (type->subtype)
{
case TYPE_COMPRESSED_NONE:
break;
case TYPE_COMPRESSED_PTR:
fputs("*", file);
break;
case TYPE_COMPRESSED_SUB:
fputs("[]", file);
break;
case TYPE_COMPRESSED_SUBPTR:
fputs("[]*", file);
break;
case TYPE_COMPRESSED_PTRPTR:
fputs("**", file);
break;
case TYPE_COMPRESSED_PTRSUB:
fputs("*[]", file);
break;
case TYPE_COMPRESSED_SUBSUB:
fputs("[][]", file);
break;
}
}
static inline void emit_func_data(FILE *file, Module *module, Decl *func)
{
fprintf(file, "\t\t\"%s::%s\": {\n", module->name->module, func->name);
fprintf(file, "\t\t\t\"rtype\": \"");
print_type(file, type_infoptr(func->func_decl.signature.rtype));
fprintf(file, "\",\n");
fputs("\t\t\t\"params\": [\n", file);
FOREACH_BEGIN_IDX(i, Decl *decl, func->func_decl.signature.params)
if (i != 0) fputs(",\n", file);
if (!decl) continue;
fputs("\t\t\t\t{\n", file);
fprintf(file, "\t\t\t\t\t\"name\": \"%s\",\n", decl->name ? decl->name : "");
fprintf(file, "\t\t\t\t\t\"type\": \"");
if (decl->var.type_info)
{
print_type(file, decl->var.type_info);
}
else
{
fputs("", file);
}
fputs("\"\n", file);
fputs("\t\t\t\t}", file);
FOREACH_END();
fputs("\n\t\t\t]\n", file);
fputs("\n\t\t}", file);
}
static inline bool decl_is_hidden(Decl *decl)
{
return decl->visibility > VISIBLE_PUBLIC;
}
static inline void emit_types(FILE *file)
{
fputs("\t\"types\": {\n", file);
{
bool first = true;
FOREACH_DECL(Decl *type, global_context.module_list)
if (!decl_is_user_defined_type(type) && type->decl_kind != DECL_TYPEDEF) continue;
if (decl_is_hidden(type)) continue;
INERT_COMMA;
emit_type_data(file, module, type);
FOREACH_DECL_END;
}
fputs("\n\t},\n", file);
fputs("\t\"generic_types\": {\n", file);
{
bool first = true;
FOREACH_DECL(Decl *type, global_context.generic_module_list)
if (!decl_is_user_defined_type(type) && type->decl_kind != DECL_TYPEDEF) continue;
if (decl_is_hidden(type)) continue;
INERT_COMMA;
emit_type_data(file, module, type);
FOREACH_DECL_END;
}
fputs("\n\t}\n", file);
}
static inline void emit_functions(FILE *file)
{
fputs("\t\"functions\": {\n", file);
{
bool first = true;
FOREACH_DECL(Decl *func, global_context.module_list)
if (func->decl_kind != DECL_FUNC) continue;
if (decl_is_hidden(func)) continue;
INERT_COMMA;
emit_func_data(file, module, func);
FOREACH_DECL_END;
}
fputs("\n\t},\n", file);
fputs("\t\"generic_functions\": {\n", file);
{
bool first = true;
FOREACH_DECL(Decl *func, global_context.generic_module_list)
if (func->decl_kind != DECL_FUNC) continue;
if (decl_is_hidden(func)) continue;
INERT_COMMA;
emit_func_data(file, module, func);
FOREACH_DECL_END;
}
fputs("\n\t},\n", file);
}
static inline void emit_json_to_file(FILE *file)
{
fputs("{\n", file);
emit_modules(file);
emit_types(file);
emit_functions(file);
fputs("\n}", file);
}
void emit_json(void)
{
emit_json_to_file(stdout);
}

View File

@@ -5855,6 +5855,9 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type
goto DONE;
}
// return foo() where foo() is a void!
if (type_no_optional(type_flatten(ret_expr->type)) == type_void) break;
LLVMInstructionEraseFromParent(exit.block_return_out);
// Restore

View File

@@ -1641,23 +1641,17 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Type
return false;
}
bool is_unused = expr->call_expr.result_unused;
if (sig->attrs.noreturn) expr->call_expr.no_return = true;
if (!sema_call_analyse_invocation(context, expr, callee, &optional)) return false;
Type *rtype = type->function.prototype->rtype;
if (is_unused && rtype != type_void)
expr->call_expr.has_optional_arg = optional;
if (rtype != type_void)
{
if (sig->attrs.nodiscard) RETURN_SEMA_ERROR(expr, "The result of the function must be used.");
if (type_is_optional(rtype) && !sig->attrs.maydiscard)
{
RETURN_SEMA_ERROR(expr, "The optional result of the function must be used.");
}
expr->call_expr.must_use = sig->attrs.nodiscard || (type_is_optional(rtype) && !sig->attrs.maydiscard);
}
expr->type = type_add_optional(rtype, optional);
return true;
@@ -1784,7 +1778,7 @@ static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr,
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool optional)
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool call_var_optional)
{
assert(decl->decl_kind == DECL_MACRO);
@@ -1802,19 +1796,21 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
Ast *body = copy_ast_macro(astptr(decl->func_decl.body));
AstId docs = decl->func_decl.docs;
if (docs) docs = astid(copy_ast_macro(astptr(docs)));
Signature *sig = &decl->func_decl.signature;
copy_end();
CalledDecl callee = {
.macro = true,
.name = decl->name,
.params = params,
.block_parameter = decl->func_decl.body_param ? declptr(decl->func_decl.body_param)->name : NULL,
.signature = &decl->func_decl.signature,
.signature = sig,
.struct_var = struct_var
};
if (!sema_call_analyse_invocation(context, call_expr, callee, &optional)) return false;
bool has_optional_arg = call_var_optional;
if (!sema_call_analyse_invocation(context, call_expr, callee, &has_optional_arg)) return false;
unsigned vararg_index = decl->func_decl.signature.vararg_index;
unsigned vararg_index = sig->vararg_index;
Expr **args = call_expr->call_expr.arguments;
VECEACH(params, i)
{
@@ -1825,7 +1821,6 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
// Splat? That's the simple case.
if (call_expr->call_expr.splat_vararg)
{
if (!sema_analyse_expr(context, args[i] = call_expr->call_expr.splat)) return false;
}
else
@@ -1840,6 +1835,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
}
}
param->var.init_expr = args[i];
has_optional_arg = has_optional_arg || IS_OPTIONAL(args[i]);
}
Decl **body_params = call_expr->call_expr.body_arguments;
@@ -1896,21 +1892,11 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
macro_context.compilation_unit = context->unit;
macro_context.macro_call_depth = context->macro_call_depth + 1;
macro_context.call_env = context->call_env;
rtype = decl->func_decl.signature.rtype ? type_infoptr(decl->func_decl.signature.rtype)->type : NULL;
rtype = typeinfotype(sig->rtype);
macro_context.expected_block_type = rtype;
bool may_be_optional = true;
if (rtype)
{
if (type_is_optional(rtype))
{
optional = true;
rtype = type_no_optional(rtype);
}
else
{
may_be_optional = false;
}
}
bool optional_return = rtype && type_is_optional(rtype);
bool may_be_optional = !rtype || optional_return;
if (rtype) rtype = type_no_optional(rtype);
context_change_scope_with_flags(&macro_context, SCOPE_MACRO);
@@ -1945,7 +1931,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
if (!sema_analyse_statement(&macro_context, body)) goto EXIT_FAIL;
params = macro_context.macro_params;
bool is_no_return = decl->func_decl.signature.attrs.noreturn;
bool is_no_return = sig->attrs.noreturn;
if (!vec_size(macro_context.returns))
{
@@ -2003,34 +1989,23 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
type_quoted_error_string(type));
goto EXIT_FAIL;
}
if (may_be_optional) ret_expr->type = type_add_optional(ret_expr->type, may_be_optional);
ret_expr->type = type_add_optional(ret_expr->type, optional_return);
}
call_expr->type = type_add_optional(rtype, optional);
call_expr->type = type_add_optional(rtype, optional_return || has_optional_arg);
}
else
{
Type *sum_returns = context_unify_returns(&macro_context);
if (!sum_returns) goto EXIT_FAIL;
call_expr->type = type_add_optional(sum_returns, optional);
optional_return = type_is_optional(sum_returns);
call_expr->type = type_add_optional(sum_returns, optional_return || has_optional_arg);
}
assert(call_expr->type);
if (call_expr->call_expr.result_unused)
bool must_use = false;
if (rtype != type_void)
{
Type *type = call_expr->type;
if (type != type_void)
{
if (decl->func_decl.signature.attrs.nodiscard)
{
SEMA_ERROR(call_expr, "The result of the macro must be used.");
goto EXIT_FAIL;
}
if (type_is_optional(type) && !decl->func_decl.signature.attrs.maydiscard)
{
SEMA_ERROR(call_expr, "The optional result of the macro must be used.");
goto EXIT_FAIL;
}
}
must_use = sig->attrs.nodiscard || (optional_return && !sig->attrs.maydiscard);
}
unsigned returns_found = vec_size(macro_context.returns);
// We may have zero normal macro returns but the active scope still has a "jump end".
@@ -2039,12 +2014,28 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
{
is_no_return = true;
}
if (returns_found)
if (returns_found == 1)
{
Ast *ret = macro_context.returns[0];
Expr *result = ret ? ret->return_stmt.expr : NULL;
if (!result) goto NOT_CT;
if (!expr_is_constant_eval(result, CONSTANT_EVAL_CONSTANT_VALUE)) goto NOT_CT;
bool only_ct_params = true;
VECEACH(params, i)
{
Decl *param = params[i];
// Skip raw vararg
if (!param) continue;
switch (param->var.kind)
{
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_PARAM_EXPR:
break;
default:
goto NOT_CT;
}
}
if (ast_is_compile_time(body))
{
expr_replace(call_expr, result);
@@ -2053,6 +2044,8 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
}
NOT_CT:
call_expr->expr_kind = EXPR_MACRO_BLOCK;
call_expr->macro_block.had_optional_arg = has_optional_arg;
call_expr->macro_block.is_must_use = must_use;
call_expr->macro_block.first_stmt = body->compound_stmt.first_stmt;
call_expr->macro_block.params = params;
call_expr->macro_block.block_exit = block_exit_ref;
@@ -4193,7 +4186,8 @@ static inline bool sema_expr_analyse_expr_list(SemaContext *context, Expr *expr)
VECEACH(expr->expression_list, i)
{
Expr *checked_expr = expr->expression_list[i];
success &= sema_analyse_expr(context, checked_expr);
if (!sema_analyse_expr(context, checked_expr)) return false;
if (i != last && !sema_expr_check_discard(checked_expr)) return false;
}
expr->type = expr->expression_list[last]->type;
return success;
@@ -7907,6 +7901,27 @@ bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr)
}
}
bool sema_expr_check_discard(Expr *expr)
{
if (!IS_OPTIONAL(expr)) return true;
if (expr->expr_kind == EXPR_SUBSCRIPT_ASSIGN || expr->expr_kind == EXPR_SLICE_ASSIGN) return true;
if (expr->expr_kind == EXPR_BINARY && expr->binary_expr.operator >= BINARYOP_ASSIGN) return true;
if (expr->expr_kind == EXPR_MACRO_BLOCK)
{
if (expr->macro_block.is_must_use) RETURN_SEMA_ERROR(expr, "The result of the macro must be used.");
if (expr->macro_block.had_optional_arg) goto ERROR_ARGS;
return true;
}
if (expr->expr_kind == EXPR_CALL)
{
if (expr->call_expr.must_use) RETURN_SEMA_ERROR(expr, "The result of the function must be used.");
if (expr->call_expr.has_optional_arg) goto ERROR_ARGS;
return true;
}
RETURN_SEMA_ERROR(expr, "An optional value may not be discarded, you can ignore it with a void cast '(void)', rethrow on optional with '!' or panic '!!' to avoid this error.");
ERROR_ARGS:
RETURN_SEMA_ERROR(expr, "The result of this call is optional due to its argument(s). The optional result may not be implicitly discarded. Consider using '(void)', '!' or '!!' to handle this.");
}
bool sema_analyse_expr(SemaContext *context, Expr *expr)
{

View File

@@ -1040,11 +1040,8 @@ static inline bool sema_analyse_declare_stmt(SemaContext *context, Ast *statemen
static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement)
{
Expr *expr = statement->expr_stmt;
if (expr->expr_kind == EXPR_CALL)
{
expr->call_expr.result_unused = true;
}
if (!sema_analyse_expr(context, expr)) return false;
if (!sema_expr_check_discard(expr)) return false;
switch (expr->expr_kind)
{
case EXPR_CALL:

View File

@@ -301,33 +301,8 @@ static void assign_panicfn(void)
*/
void sema_analysis_run(void)
{
// Cleanup any errors (could there really be one here?!)
global_context_clear_errors();
// Add the standard library
if (global_context.lib_dir && !active_target.no_stdlib)
{
file_add_wildcard_files(&global_context.sources, global_context.lib_dir, true, c3_suffix_list, 3);
}
// Load and parse all files.
bool has_error = false;
VECEACH(global_context.sources, i)
{
bool loaded = false;
const char *error;
File *file = source_file_load(global_context.sources[i], &loaded, &error);
if (!file) error_exit(error);
if (loaded) continue;
if (!parse_file(file)) has_error = true;
}
if (active_target.read_stdin)
{
if (!parse_stdin()) has_error = true;
}
if (has_error) exit_compiler(EXIT_FAILURE);
compiler_parsing_time = bench_mark();
compiler_parse();
// All global defines are added to the std module
global_context.std_module_path = (Path) { .module = kw_std, .span = INVALID_SPAN, .len = (uint32_t) strlen(kw_std) };

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.583"
#define COMPILER_VERSION "0.4.584"

View File

@@ -7,7 +7,7 @@ fn int! bar()
defer {
{|
foo()!;
|};
|}!!;
}
defer foo()!; // #error: Rethrows are not allowed inside of defers.
return 1;

View File

@@ -19,12 +19,12 @@ fn int main()
int! b = foo((a + 3) ?? 2);
int! c = foo(0);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
(void)printf("a = %d\n", a);
(void)printf("b = %d\n", b);
(void)printf("c = %d\n", c);
if (@catchof(c)) printf("c had error\n");
c = 3;
printf("c = %d\n", c);
(void)printf("c = %d\n", c);
return 0;
}

View File

@@ -10,8 +10,8 @@ fn void test1()
int! b = a = Test.FOO?;
if (catch err = a) io::printfn("A err was: %s", err);
if (catch err = b) io::printfn("B err was: %s", err);
io::printfn("A was: %s", a);
io::printfn("B was: %s", b);
(void)io::printfn("A was: %s", a);
(void)io::printfn("B was: %s", b);
}
fn void test2()
@@ -21,8 +21,8 @@ fn void test2()
int! b = a = x;
if (catch err = a) io::printfn("A err was: %s", err);
if (catch err = b) io::printfn("B err was: %s", err);
io::printfn("A was: %s", a);
io::printfn("B was: %s", b);
(void)io::printfn("A was: %s", a);
(void)io::printfn("B was: %s", b);
}
@@ -33,8 +33,8 @@ fn void test3()
int! b = a = x;
if (catch err = a) io::printfn("A err was: %s", err);
if (catch err = b) io::printfn("B err was: %s", err);
io::printfn("A was: %s", a);
io::printfn("B was: %s", b);
(void)io::printfn("A was: %s", a);
(void)io::printfn("B was: %s", b);
}
fn void main()

View File

@@ -0,0 +1,54 @@
fn int abc(int x) { return 1; }
fn int! def2(int y) @maydiscard { return 1; }
fn int! def3(int z) { return 1; }
fn void test1()
{
int! x;
abc(x); // #error: The result of this call is optional due to its argumen
}
fn void test2()
{
int! x;
int y;
abc(y);
abc(x) + 4; // #error: An optional value may not be discarded
}
fn void test3()
{
int! x;
int y;
def2(1);
def2(x); // #error: The result of this call is optional due to its argumen
}
fn void test4()
{
int! x;
int y;
def2(1);
def2(x) + 4; // #error: An optional value may not be discarded
}
fn void test5()
{
int! x;
int y;
def3(y); // #error: The result of the function must be used
}
fn void test6()
{
int! x;
int y;
def3(x); // #error: The result of the function must be used
}
fn void test7()
{
int y;
def3(y) + 4; // #error: An optional value may not be discarded
}

View File

@@ -0,0 +1,54 @@
macro int abc(int x) { return 1; }
macro int! def2(int y) @maydiscard { return 1; }
macro int! def3(int z) { return 1; }
fn void test1()
{
int! x;
abc(x); // #error: The result of this call is optional due to its argumen
}
fn void test2()
{
int! x;
int y;
abc(y);
abc(x) + 4; // #error: An optional value may not be discarded
}
fn void test3()
{
int! x;
int y;
def2(1);
def2(x); // #error: The result of this call is optional due to its argumen
}
fn void test4()
{
int! x;
int y;
def2(1);
def2(x) + 4; // #error: An optional value may not be discarded
}
fn void test5()
{
int! x;
int y;
def3(y); // #error: The result of the macro must
}
fn void test6()
{
int! x;
int y;
def3(x); // #error: The result of the macro must
}
fn void test7()
{
int y;
def3(y) + 4; // #error: An optional value may not be discarded
}

View File

@@ -17,10 +17,10 @@ fn void main()
{
int! z = 2;
Foo*! w = &&Foo{ z, 0 };
printf("%d\n", w.x);
(void)printf("%d\n", w.x);
z = MyErr.FOO?;
w = &&Foo{ z, 0 };
printf("Not visible: %d\n", w.x);
(void)printf("Not visible: %d\n", w.x);
}
/* #expect: test.ll

View File

@@ -6,7 +6,7 @@ fn void main()
{
Foo a = 12.3;
Foo! b = 33.5;
printf("%f %f %f", (float)a, a, b);
(void)printf("%f %f %f", (float)a, a, b);
}
/* #expect: test.ll

View File

@@ -0,0 +1,9 @@
module abi;
fn void! abc() {}
macro void! abc_macro() => abc();
fn void main()
{
(void)abc_macro();
}

View File

@@ -84,7 +84,6 @@ fn void main()
/* #expect: foo.ll
%Foo = type { [3 x i32] }
@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 12, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [11 x i8] c"getFields\0A\00", align 1
@.__const = private unnamed_addr constant [5 x i32] [i32 3, i32 5, i32 2, i32 10, i32 111], align 16
@@ -102,10 +101,8 @@ fn void main()
@.str.12 = private unnamed_addr constant [27 x i8] c"Pull value tempptr %d: %d\0A\00", align 1
@.str.13 = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1
@.str.14 = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1
; Function Attrs: nounwind
declare void @printf(ptr, ...) #0
; Function Attrs: nounwind
define void @foo.getFields(ptr noalias sret([5 x i32]) align 4 %0) #0 {
entry:
@@ -115,14 +112,12 @@ entry:
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %0, ptr align 4 %literal, i32 20, i1 false)
ret void
}
; Function Attrs: nounwind
define ptr @foo.call(ptr %0) #0 {
entry:
call void (ptr, ...) @printf(ptr @.str.1)
ret ptr %0
}
; Function Attrs: nounwind
define void @foo.main() #0 {
entry:
@@ -180,264 +175,241 @@ entry:
call void (ptr, ...) @printf(ptr @.str.3, i32 %2, i32 %5, i32 %8)
%9 = call ptr @foo.call(ptr %x)
store ptr %9, ptr %.anon, align 8
%10 = load ptr, ptr %.anon, align 8
store i32 3, ptr %.anon1, align 4
store i32 0, ptr %.anon2, align 4
br label %loop.cond
loop.cond: ; preds = %loop.body, %entry
%10 = load i32, ptr %.anon2, align 4
%11 = load i32, ptr %.anon1, align 4
%lt = icmp slt i32 %10, %11
%11 = load i32, ptr %.anon2, align 4
%12 = load i32, ptr %.anon1, align 4
%lt = icmp slt i32 %11, %12
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%12 = load i32, ptr %.anon2, align 4
store i32 %12, ptr %i, align 4
%13 = load ptr, ptr %.anon, align 8
%14 = load i32, ptr %.anon2, align 4
store i32 %14, ptr %a, align 4
%15 = getelementptr inbounds %Foo, ptr %13, i32 0, i32 0
%16 = load i32, ptr %a, align 4
%sext = sext i32 %16 to i64
%17 = getelementptr inbounds [3 x i32], ptr %15, i64 0, i64 %sext
%18 = load i32, ptr %17, align 4
store i32 %18, ptr %y, align 4
%19 = load i32, ptr %i, align 4
%20 = load i32, ptr %y, align 4
call void (ptr, ...) @printf(ptr @.str.4, i32 %19, i32 %20)
%21 = load i32, ptr %.anon2, align 4
%add = add i32 %21, 1
%13 = load i32, ptr %.anon2, align 4
store i32 %13, ptr %i, align 4
%14 = load ptr, ptr %.anon, align 8
%15 = load i32, ptr %.anon2, align 4
store i32 %15, ptr %a, align 4
%16 = getelementptr inbounds %Foo, ptr %14, i32 0, i32 0
%17 = load i32, ptr %a, align 4
%sext = sext i32 %17 to i64
%18 = getelementptr inbounds [3 x i32], ptr %16, i64 0, i64 %sext
%19 = load i32, ptr %18, align 4
store i32 %19, ptr %y, align 4
%20 = load i32, ptr %i, align 4
%21 = load i32, ptr %y, align 4
call void (ptr, ...) @printf(ptr @.str.4, i32 %20, i32 %21)
%22 = load i32, ptr %.anon2, align 4
%add = add i32 %22, 1
store i32 %add, ptr %.anon2, align 4
br label %loop.cond
loop.exit: ; preds = %loop.cond
store i32 3, ptr %.anon3, align 4
store i32 0, ptr %.anon4, align 4
br label %loop.cond5
loop.cond5: ; preds = %loop.body7, %loop.exit
%22 = load i32, ptr %.anon4, align 4
%23 = load i32, ptr %.anon3, align 4
%lt6 = icmp slt i32 %22, %23
%23 = load i32, ptr %.anon4, align 4
%24 = load i32, ptr %.anon3, align 4
%lt6 = icmp slt i32 %23, %24
br i1 %lt6, label %loop.body7, label %loop.exit14
loop.body7: ; preds = %loop.cond5
%24 = load i32, ptr %.anon4, align 4
store i32 %24, ptr %i8, align 4
%25 = load i32, ptr %.anon4, align 4
store i32 %25, ptr %a10, align 4
%26 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%27 = load i32, ptr %a10, align 4
%sext11 = sext i32 %27 to i64
%28 = getelementptr inbounds [3 x i32], ptr %26, i64 0, i64 %sext11
store ptr %28, ptr %y9, align 8
%29 = load ptr, ptr %y9, align 8
%30 = load i32, ptr %29, align 4
%add12 = add i32 %30, 1
store i32 %add12, ptr %29, align 4
%31 = load i32, ptr %i8, align 4
%32 = load ptr, ptr %y9, align 8
%33 = load i32, ptr %32, align 4
call void (ptr, ...) @printf(ptr @.str.5, i32 %31, i32 %33)
%34 = load i32, ptr %.anon4, align 4
%add13 = add i32 %34, 1
store i32 %25, ptr %i8, align 4
%26 = load i32, ptr %.anon4, align 4
store i32 %26, ptr %a10, align 4
%27 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%28 = load i32, ptr %a10, align 4
%sext11 = sext i32 %28 to i64
%29 = getelementptr inbounds [3 x i32], ptr %27, i64 0, i64 %sext11
store ptr %29, ptr %y9, align 8
%30 = load ptr, ptr %y9, align 8
%31 = load i32, ptr %30, align 4
%add12 = add i32 %31, 1
store i32 %add12, ptr %30, align 4
%32 = load i32, ptr %i8, align 4
%33 = load ptr, ptr %y9, align 8
%34 = load i32, ptr %33, align 4
call void (ptr, ...) @printf(ptr @.str.5, i32 %32, i32 %34)
%35 = load i32, ptr %.anon4, align 4
%add13 = add i32 %35, 1
store i32 %add13, ptr %.anon4, align 4
br label %loop.cond5
loop.exit14: ; preds = %loop.cond5
store i32 3, ptr %.anon15, align 4
store i32 0, ptr %.anon16, align 4
br label %loop.cond17
loop.cond17: ; preds = %loop.body19, %loop.exit14
%35 = load i32, ptr %.anon16, align 4
%36 = load i32, ptr %.anon15, align 4
%lt18 = icmp slt i32 %35, %36
%36 = load i32, ptr %.anon16, align 4
%37 = load i32, ptr %.anon15, align 4
%lt18 = icmp slt i32 %36, %37
br i1 %lt18, label %loop.body19, label %loop.exit25
loop.body19: ; preds = %loop.cond17
%37 = load i32, ptr %.anon16, align 4
store i32 %37, ptr %i20, align 4
%38 = load i32, ptr %.anon16, align 4
store i32 %38, ptr %a22, align 4
%39 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%40 = load i32, ptr %a22, align 4
%sext23 = sext i32 %40 to i64
%41 = getelementptr inbounds [3 x i32], ptr %39, i64 0, i64 %sext23
%42 = load i32, ptr %41, align 4
store i32 %42, ptr %y21, align 4
%43 = load i32, ptr %i20, align 4
%44 = load i32, ptr %y21, align 4
call void (ptr, ...) @printf(ptr @.str.6, i32 %43, i32 %44)
%45 = load i32, ptr %.anon16, align 4
%add24 = add i32 %45, 1
store i32 %38, ptr %i20, align 4
%39 = load i32, ptr %.anon16, align 4
store i32 %39, ptr %a22, align 4
%40 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%41 = load i32, ptr %a22, align 4
%sext23 = sext i32 %41 to i64
%42 = getelementptr inbounds [3 x i32], ptr %40, i64 0, i64 %sext23
%43 = load i32, ptr %42, align 4
store i32 %43, ptr %y21, align 4
%44 = load i32, ptr %i20, align 4
%45 = load i32, ptr %y21, align 4
call void (ptr, ...) @printf(ptr @.str.6, i32 %44, i32 %45)
%46 = load i32, ptr %.anon16, align 4
%add24 = add i32 %46, 1
store i32 %add24, ptr %.anon16, align 4
br label %loop.cond17
loop.exit25: ; preds = %loop.cond17
store i32 3, ptr %.anon26, align 4
store i32 0, ptr %.anon27, align 4
br label %loop.cond28
loop.cond28: ; preds = %loop.body30, %loop.exit25
%46 = load i32, ptr %.anon27, align 4
%47 = load i32, ptr %.anon26, align 4
%lt29 = icmp slt i32 %46, %47
%47 = load i32, ptr %.anon27, align 4
%48 = load i32, ptr %.anon26, align 4
%lt29 = icmp slt i32 %47, %48
br i1 %lt29, label %loop.body30, label %loop.exit36
loop.body30: ; preds = %loop.cond28
%48 = load i32, ptr %.anon27, align 4
store i32 %48, ptr %i31, align 4
%49 = load i32, ptr %.anon27, align 4
store i32 %49, ptr %a33, align 4
%50 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%51 = load i32, ptr %a33, align 4
%sext34 = sext i32 %51 to i64
%52 = getelementptr inbounds [3 x i32], ptr %50, i64 0, i64 %sext34
%53 = load i32, ptr %52, align 4
store i32 %53, ptr %y32, align 4
%54 = load i32, ptr %i31, align 4
%55 = load i32, ptr %y32, align 4
call void (ptr, ...) @printf(ptr @.str.7, i32 %54, i32 %55)
%56 = load i32, ptr %.anon27, align 4
%add35 = add i32 %56, 1
store i32 %49, ptr %i31, align 4
%50 = load i32, ptr %.anon27, align 4
store i32 %50, ptr %a33, align 4
%51 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%52 = load i32, ptr %a33, align 4
%sext34 = sext i32 %52 to i64
%53 = getelementptr inbounds [3 x i32], ptr %51, i64 0, i64 %sext34
%54 = load i32, ptr %53, align 4
store i32 %54, ptr %y32, align 4
%55 = load i32, ptr %i31, align 4
%56 = load i32, ptr %y32, align 4
call void (ptr, ...) @printf(ptr @.str.7, i32 %55, i32 %56)
%57 = load i32, ptr %.anon27, align 4
%add35 = add i32 %57, 1
store i32 %add35, ptr %.anon27, align 4
br label %loop.cond28
loop.exit36: ; preds = %loop.cond28
store i32 3, ptr %.anon37, align 4
store i32 0, ptr %.anon38, align 4
br label %loop.cond39
loop.cond39: ; preds = %loop.body41, %loop.exit36
%57 = load i32, ptr %.anon38, align 4
%58 = load i32, ptr %.anon37, align 4
%lt40 = icmp slt i32 %57, %58
%58 = load i32, ptr %.anon38, align 4
%59 = load i32, ptr %.anon37, align 4
%lt40 = icmp slt i32 %58, %59
br i1 %lt40, label %loop.body41, label %loop.exit48
loop.body41: ; preds = %loop.cond39
%59 = load i32, ptr %.anon38, align 4
store i32 %59, ptr %i42, align 4
%60 = load i32, ptr %.anon38, align 4
store i32 %60, ptr %a44, align 4
%61 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%62 = load i32, ptr %a44, align 4
%sext45 = sext i32 %62 to i64
%63 = getelementptr inbounds [3 x i32], ptr %61, i64 0, i64 %sext45
%64 = load i32, ptr %63, align 4
store i32 %64, ptr %y43, align 4
%65 = load i32, ptr %i42, align 4
%66 = load i32, ptr %y43, align 4
call void (ptr, ...) @printf(ptr @.str.8, i32 %65, i32 %66)
%67 = load i32, ptr %i42, align 4
%add46 = add i32 %67, 1
store i32 %60, ptr %i42, align 4
%61 = load i32, ptr %.anon38, align 4
store i32 %61, ptr %a44, align 4
%62 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%63 = load i32, ptr %a44, align 4
%sext45 = sext i32 %63 to i64
%64 = getelementptr inbounds [3 x i32], ptr %62, i64 0, i64 %sext45
%65 = load i32, ptr %64, align 4
store i32 %65, ptr %y43, align 4
%66 = load i32, ptr %i42, align 4
%67 = load i32, ptr %y43, align 4
call void (ptr, ...) @printf(ptr @.str.8, i32 %66, i32 %67)
%68 = load i32, ptr %i42, align 4
%add46 = add i32 %68, 1
store i32 %add46, ptr %i42, align 4
%68 = load i32, ptr %.anon38, align 4
%add47 = add i32 %68, 1
%69 = load i32, ptr %.anon38, align 4
%add47 = add i32 %69, 1
store i32 %add47, ptr %.anon38, align 4
br label %loop.cond39
loop.exit48: ; preds = %loop.cond39
call void @llvm.memcpy.p0.p0.i32(ptr align 16 %.anon49, ptr align 16 @.__const.9, i32 20, i1 false)
store i64 0, ptr %.anon50, align 8
br label %loop.cond51
loop.cond51: ; preds = %loop.body52, %loop.exit48
%69 = load i64, ptr %.anon50, align 8
%gt = icmp ugt i64 5, %69
br i1 %gt, label %loop.body52, label %loop.exit57
loop.body52: ; preds = %loop.cond51
%70 = load i64, ptr %.anon50, align 8
store i64 %70, ptr %i53, align 8
%gt = icmp ugt i64 5, %70
br i1 %gt, label %loop.body52, label %loop.exit57
loop.body52: ; preds = %loop.cond51
%71 = load i64, ptr %.anon50, align 8
%72 = getelementptr inbounds [5 x i32], ptr %.anon49, i64 0, i64 %71
%73 = load i32, ptr %72, align 4
store i32 %73, ptr %y54, align 4
%74 = load i64, ptr %i53, align 8
%75 = load i32, ptr %y54, align 4
call void (ptr, ...) @printf(ptr @.str.10, i64 %74, i32 %75)
%76 = load i64, ptr %i53, align 8
%add55 = add i64 %76, 1
store i64 %71, ptr %i53, align 8
%72 = load i64, ptr %.anon50, align 8
%73 = getelementptr inbounds [5 x i32], ptr %.anon49, i64 0, i64 %72
%74 = load i32, ptr %73, align 4
store i32 %74, ptr %y54, align 4
%75 = load i64, ptr %i53, align 8
%76 = load i32, ptr %y54, align 4
call void (ptr, ...) @printf(ptr @.str.10, i64 %75, i32 %76)
%77 = load i64, ptr %i53, align 8
%add55 = add i64 %77, 1
store i64 %add55, ptr %i53, align 8
%77 = load i64, ptr %.anon50, align 8
%add56 = add i64 %77, 1
%78 = load i64, ptr %.anon50, align 8
%add56 = add i64 %78, 1
store i64 %add56, ptr %.anon50, align 8
br label %loop.cond51
loop.exit57: ; preds = %loop.cond51
call void @foo.getFields(ptr sret([5 x i32]) align 4 %.anon58)
store i64 0, ptr %.anon59, align 8
br label %loop.cond60
loop.cond60: ; preds = %loop.body62, %loop.exit57
%78 = load i64, ptr %.anon59, align 8
%gt61 = icmp ugt i64 5, %78
br i1 %gt61, label %loop.body62, label %loop.exit66
loop.body62: ; preds = %loop.cond60
%79 = load i64, ptr %.anon59, align 8
store i64 %79, ptr %i63, align 8
%gt61 = icmp ugt i64 5, %79
br i1 %gt61, label %loop.body62, label %loop.exit66
loop.body62: ; preds = %loop.cond60
%80 = load i64, ptr %.anon59, align 8
%81 = getelementptr inbounds [5 x i32], ptr %.anon58, i64 0, i64 %80
%82 = load i32, ptr %81, align 4
store i32 %82, ptr %y64, align 4
%83 = load i64, ptr %i63, align 8
%84 = load i32, ptr %y64, align 4
call void (ptr, ...) @printf(ptr @.str.11, i64 %83, i32 %84)
%85 = load i64, ptr %.anon59, align 8
%add65 = add i64 %85, 1
store i64 %80, ptr %i63, align 8
%81 = load i64, ptr %.anon59, align 8
%82 = getelementptr inbounds [5 x i32], ptr %.anon58, i64 0, i64 %81
%83 = load i32, ptr %82, align 4
store i32 %83, ptr %y64, align 4
%84 = load i64, ptr %i63, align 8
%85 = load i32, ptr %y64, align 4
call void (ptr, ...) @printf(ptr @.str.11, i64 %84, i32 %85)
%86 = load i64, ptr %.anon59, align 8
%add65 = add i64 %86, 1
store i64 %add65, ptr %.anon59, align 8
br label %loop.cond60
loop.exit66: ; preds = %loop.cond60
call void @foo.getFields(ptr sret([5 x i32]) align 4 %sretparam)
store ptr %sretparam, ptr %.anon67, align 8
store i64 0, ptr %.anon68, align 8
br label %loop.cond69
loop.cond69: ; preds = %loop.body71, %loop.exit66
%86 = load i64, ptr %.anon68, align 8
%gt70 = icmp ugt i64 5, %86
br i1 %gt70, label %loop.body71, label %loop.exit75
loop.body71: ; preds = %loop.cond69
%87 = load i64, ptr %.anon68, align 8
store i64 %87, ptr %i72, align 8
%88 = load ptr, ptr %.anon67, align 8
%89 = load i64, ptr %.anon68, align 8
%90 = getelementptr inbounds [5 x i32], ptr %88, i64 0, i64 %89
%91 = load i32, ptr %90, align 4
store i32 %91, ptr %y73, align 4
%92 = load i64, ptr %i72, align 8
%93 = load i32, ptr %y73, align 4
call void (ptr, ...) @printf(ptr @.str.12, i64 %92, i32 %93)
%94 = load i64, ptr %.anon68, align 8
%add74 = add i64 %94, 1
%gt70 = icmp ugt i64 5, %87
br i1 %gt70, label %loop.body71, label %loop.exit75
loop.body71: ; preds = %loop.cond69
%88 = load i64, ptr %.anon68, align 8
store i64 %88, ptr %i72, align 8
%89 = load ptr, ptr %.anon67, align 8
%90 = load i64, ptr %.anon68, align 8
%91 = getelementptr inbounds [5 x i32], ptr %89, i64 0, i64 %90
%92 = load i32, ptr %91, align 4
store i32 %92, ptr %y73, align 4
%93 = load i64, ptr %i72, align 8
%94 = load i32, ptr %y73, align 4
call void (ptr, ...) @printf(ptr @.str.12, i64 %93, i32 %94)
%95 = load i64, ptr %.anon68, align 8
%add74 = add i64 %95, 1
store i64 %add74, ptr %.anon68, align 8
br label %loop.cond69
loop.exit75: ; preds = %loop.cond69
%95 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%96 = getelementptr inbounds [3 x i32], ptr %95, i64 0, i64 0
%97 = load i32, ptr %96, align 4
%98 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%99 = getelementptr inbounds [3 x i32], ptr %98, i64 0, i64 1
%100 = load i32, ptr %99, align 4
call void (ptr, ...) @printf(ptr @.str.13, i32 %97, i32 %100)
%101 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%102 = getelementptr inbounds [3 x i32], ptr %101, i64 0, i64 1
store ptr %102, ptr %y76, align 8
%103 = load ptr, ptr %y76, align 8
%104 = load i32, ptr %103, align 4
%add77 = add i32 %104, 1
store i32 %add77, ptr %103, align 4
%105 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%106 = getelementptr inbounds [3 x i32], ptr %105, i64 0, i64 0
%107 = load i32, ptr %106, align 4
%108 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%109 = getelementptr inbounds [3 x i32], ptr %108, i64 0, i64 1
%110 = load i32, ptr %109, align 4
call void (ptr, ...) @printf(ptr @.str.14, i32 %107, i32 %110)
%96 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%97 = getelementptr inbounds [3 x i32], ptr %96, i64 0, i64 0
%98 = load i32, ptr %97, align 4
%99 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%100 = getelementptr inbounds [3 x i32], ptr %99, i64 0, i64 1
%101 = load i32, ptr %100, align 4
call void (ptr, ...) @printf(ptr @.str.13, i32 %98, i32 %101)
%102 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%103 = getelementptr inbounds [3 x i32], ptr %102, i64 0, i64 1
store ptr %103, ptr %y76, align 8
%104 = load ptr, ptr %y76, align 8
%105 = load i32, ptr %104, align 4
%add77 = add i32 %105, 1
store i32 %add77, ptr %104, align 4
%106 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%107 = getelementptr inbounds [3 x i32], ptr %106, i64 0, i64 0
%108 = load i32, ptr %107, align 4
%109 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0
%110 = getelementptr inbounds [3 x i32], ptr %109, i64 0, i64 1
%111 = load i32, ptr %110, align 4
call void (ptr, ...) @printf(ptr @.str.14, i32 %108, i32 %111)
ret void
}

View File

@@ -27,7 +27,7 @@ fn void main()
io::printfn("Map size: %d", map.count);
map.set(1, Foo { 2, null });
io::printfn("Map size: %d", map.count);
io::printfn("Val: %d", map.get(1).x);
(void)io::printfn("Val: %d", map.get(1).x);
io::printfn("Has 1: %s", map.has_key(1));
io::printfn("Has 2: %s", map.has_key(2));
map.set(7, Foo { 4, null });