From 182cf5b8de375080bff6f2bb91cd398e776da16c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Dec 2017 12:27:29 -0500 Subject: translate-c: support macros with pointer casting --- src/ast_render.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 4f4dc1decd..d6a23e5f85 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -584,12 +584,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { PrefixOp op = node->data.prefix_op_expr.prefix_op; fprintf(ar->f, "%s", prefix_op_str(op)); - render_node_ungrouped(ar, node->data.prefix_op_expr.primary_expr); + AstNode *child_node = node->data.prefix_op_expr.primary_expr; + bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypeAddrOfExpr; + render_node_extra(ar, child_node, new_grouped); if (!grouped) fprintf(ar->f, ")"); break; } case NodeTypeAddrOfExpr: { + if (!grouped) fprintf(ar->f, "("); fprintf(ar->f, "&"); if (node->data.addr_of_expr.align_expr != nullptr) { fprintf(ar->f, "align("); @@ -617,6 +620,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } render_node_ungrouped(ar, node->data.addr_of_expr.op_expr); + if (!grouped) fprintf(ar->f, ")"); break; } case NodeTypeFnCallExpr: @@ -625,7 +629,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "@"); } AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr); + bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); render_node_extra(ar, fn_ref_node, grouped); fprintf(ar->f, "("); for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) { -- cgit v1.2.3 From 1fdebc1dc4881a00766f7c2b4b2d8ee6ad6e79b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 18 Dec 2017 09:59:57 -0500 Subject: wip export rewrite --- doc/langref.html.in | 8 +- example/hello_world/hello_libc.zig | 8 +- example/mix_o_files/base64.zig | 5 +- example/shared_library/mathtest.zig | 5 +- src/all_types.hpp | 61 +-- src/analyze.cpp | 129 +++--- src/analyze.hpp | 2 + src/ast_render.cpp | 21 +- src/codegen.cpp | 106 +++-- src/ir.cpp | 459 ++++++++++-------- src/ir_print.cpp | 40 +- src/parser.cpp | 28 +- src/tokenizer.cpp | 4 +- src/tokenizer.hpp | 2 +- src/translate_c.cpp | 6 +- std/debug.zig | 2 - std/elf.zig | 62 +-- std/mem.zig | 1 + std/os/linux.zig | 22 - std/os/linux_i386.zig | 10 - std/special/bootstrap.zig | 35 +- std/special/bootstrap_lib.zig | 6 +- std/special/builtin.zig | 36 +- std/special/compiler_rt/aulldiv.zig | 119 +++-- std/special/compiler_rt/aullrem.zig | 121 +++-- std/special/compiler_rt/comparetf2.zig | 45 +- std/special/compiler_rt/fixunsdfdi.zig | 4 +- std/special/compiler_rt/fixunsdfsi.zig | 4 +- std/special/compiler_rt/fixunsdfti.zig | 4 +- std/special/compiler_rt/fixunssfdi.zig | 4 +- std/special/compiler_rt/fixunssfsi.zig | 4 +- std/special/compiler_rt/fixunssfti.zig | 4 +- std/special/compiler_rt/fixunstfdi.zig | 4 +- std/special/compiler_rt/fixunstfsi.zig | 4 +- std/special/compiler_rt/fixunstfti.zig | 4 +- std/special/compiler_rt/index.zig | 341 +++++++------- std/special/compiler_rt/udivmoddi4.zig | 4 +- std/special/compiler_rt/udivmodti4.zig | 4 +- std/special/compiler_rt/udivti3.zig | 4 +- std/special/compiler_rt/umodti3.zig | 4 +- test/cases/asm.zig | 13 +- test/cases/misc.zig | 23 +- test/compare_output.zig | 16 +- test/compile_errors.zig | 822 +++++++++++++++++++++------------ test/standalone/issue_339/test.zig | 5 +- test/translate_c.zig | 64 +-- 46 files changed, 1486 insertions(+), 1193 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index e5b896410d..f302cbec5d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5815,13 +5815,13 @@ TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestD TestDecl = "test" String Block -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) +TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) ErrorValueDecl = "error" Symbol ";" GlobalVarDecl = VariableDeclaration ";" -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression +VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression ContainerMember = (ContainerField | FnDef | GlobalVarDecl) @@ -5831,9 +5831,7 @@ UseDecl = "use" Expression ";" ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr) - -VisibleMod = "pub" | "export" +FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) FnDef = option("inline" | "extern") FnProto Block diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index ea8aec1e4f..16d0f303cc 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -5,9 +5,13 @@ const c = @cImport({ @cInclude("string.h"); }); -const msg = c"Hello, world!\n"; +comptime { + @export("main", main); +} + +extern fn main(argc: c_int, argv: &&u8) -> c_int { + const msg = c"Hello, world!\n"; -export fn main(argc: c_int, argv: &&u8) -> c_int { if (c.printf(msg) != c_int(c.strlen(msg))) return -1; diff --git a/example/mix_o_files/base64.zig b/example/mix_o_files/base64.zig index 49c9bc6012..a8358e9685 100644 --- a/example/mix_o_files/base64.zig +++ b/example/mix_o_files/base64.zig @@ -1,6 +1,9 @@ const base64 = @import("std").base64; -export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { +comptime { + @export("decode_base_64", decode_base_64); +} +extern fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { const src = source_ptr[0..source_len]; const dest = dest_ptr[0..dest_len]; const base64_decoder = base64.standard_decoder_unsafe; diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig index a11642554f..f6d0a61c90 100644 --- a/example/shared_library/mathtest.zig +++ b/example/shared_library/mathtest.zig @@ -1,3 +1,6 @@ -export fn add(a: i32, b: i32) -> i32 { +comptime { + @export("add", add); +} +extern fn add(a: i32, b: i32) -> i32 { a + b } diff --git a/src/all_types.hpp b/src/all_types.hpp index c86b99d35c..9256777428 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -37,6 +37,7 @@ struct IrBasicBlock; struct ScopeDecls; struct ZigWindowsSDK; struct Tld; +struct TldExport; struct IrGotoItem { AstNode *source_node; @@ -272,7 +273,6 @@ enum ReturnKnowledge { enum VisibMod { VisibModPrivate, VisibModPub, - VisibModExport, }; enum GlobalLinkageId { @@ -313,11 +313,14 @@ struct TldVar { Tld base; VariableTableEntry *var; - AstNode *set_global_section_node; - Buf *section_name; - AstNode *set_global_linkage_node; - GlobalLinkageId linkage; Buf *extern_lib_name; + Buf *section_name; + + size_t export_count; + union { + TldExport *tld; // if export_count == 1 + TldExport **tld_list; // if export_count > 1 + } export_data; }; struct TldFn { @@ -432,6 +435,8 @@ struct AstNodeFnProto { Buf *lib_name; // populated if the "align A" is present AstNode *align_expr; + // populated if the "section(S)" is present + AstNode *section_expr; }; struct AstNodeFnDef { @@ -487,8 +492,10 @@ struct AstNodeVariableDeclaration { AstNode *expr; // populated if this is an extern declaration Buf *lib_name; - // populated if the "align A" is present + // populated if the "align(A)" is present AstNode *align_expr; + // populated if the "section(S)" is present + AstNode *section_expr; }; struct AstNodeErrorValueDecl { @@ -1177,6 +1184,12 @@ enum FnInline { FnInlineNever, }; +struct FnExport { + Buf name; + GlobalLinkageId linkage; + AstNode *source_node; +}; + struct FnTableEntry { LLVMValueRef llvm_value; const char *llvm_name; @@ -1204,12 +1217,11 @@ struct FnTableEntry { ZigList alloca_list; ZigList variable_list; - AstNode *set_global_section_node; Buf *section_name; - AstNode *set_global_linkage_node; - GlobalLinkageId linkage; AstNode *set_alignstack_node; uint32_t alignstack_value; + + ZigList export_list; }; uint32_t fn_table_entry_hash(FnTableEntry*); @@ -1258,8 +1270,6 @@ enum BuiltinFnId { BuiltinFnIdSetFloatMode, BuiltinFnIdTypeName, BuiltinFnIdCanImplicitCast, - BuiltinFnIdSetGlobalSection, - BuiltinFnIdSetGlobalLinkage, BuiltinFnIdPanic, BuiltinFnIdPtrCast, BuiltinFnIdBitCast, @@ -1279,6 +1289,8 @@ enum BuiltinFnId { BuiltinFnIdOpaqueType, BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, + BuiltinFnIdExport, + BuiltinFnIdExportWithLinkage, }; struct BuiltinFnEntry { @@ -1425,7 +1437,7 @@ struct CodeGen { HashMap generic_table; HashMap memoized_fn_eval_table; HashMap llvm_fn_table; - HashMap exported_symbol_names; + HashMap exported_symbol_names; HashMap external_prototypes; @@ -1886,8 +1898,6 @@ enum IrInstructionId { IrInstructionIdCheckStatementIsVoid, IrInstructionIdTypeName, IrInstructionIdCanImplicitCast, - IrInstructionIdSetGlobalSection, - IrInstructionIdSetGlobalLinkage, IrInstructionIdDeclRef, IrInstructionIdPanic, IrInstructionIdTagName, @@ -1901,6 +1911,7 @@ enum IrInstructionId { IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, + IrInstructionIdExport, }; struct IrInstruction { @@ -2626,20 +2637,6 @@ struct IrInstructionCanImplicitCast { IrInstruction *target_value; }; -struct IrInstructionSetGlobalSection { - IrInstruction base; - - Tld *tld; - IrInstruction *value; -}; - -struct IrInstructionSetGlobalLinkage { - IrInstruction base; - - Tld *tld; - IrInstruction *value; -}; - struct IrInstructionDeclRef { IrInstruction base; @@ -2728,6 +2725,14 @@ struct IrInstructionArgType { IrInstruction *arg_index; }; +struct IrInstructionExport { + IrInstruction base; + + IrInstruction *name; + IrInstruction *linkage; + IrInstruction *target; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 1d5d5e4790..84d9b9feaf 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1062,7 +1062,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; if (fn_proto->cc == CallingConventionUnspecified) { - bool extern_abi = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); + bool extern_abi = fn_proto->is_extern; fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; } else { fn_type_id->cc = fn_proto->cc; @@ -1093,6 +1093,38 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ return true; } +static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { + TypeTableEntry *ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + TypeTableEntry *str_type = get_slice_type(g, ptr_type); + IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); + if (type_is_invalid(instr->value.type)) + return false; + + ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; + + assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; + expand_undef_array(g, array_val); + size_t len = bigint_as_unsigned(&len_field->data.x_bigint); + Buf *result = buf_alloc(); + buf_resize(result, len); + for (size_t i = 0; i < len; i += 1) { + size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; + ConstExprValue *char_val = &array_val->data.x_array.s_none.elements[new_index]; + if (char_val->special == ConstValSpecialUndef) { + add_node_error(g, node, buf_sprintf("use of undefined value")); + return false; + } + uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); + assert(big_c <= UINT8_MAX); + uint8_t c = (uint8_t)big_c; + buf_ptr(result)[i] = c; + } + *out_buffer = result; + return true; +} + static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; @@ -2472,7 +2504,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { buf_append_buf(buf, tld->name); } -FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { +FnTableEntry *create_fn_raw(FnInline inline_value) { FnTableEntry *fn_entry = allocate(1); fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; @@ -2480,7 +2512,6 @@ FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->ir_executable.fn_entry = fn_entry; fn_entry->fn_inline = inline_value; - fn_entry->linkage = linkage; return fn_entry; } @@ -2490,9 +2521,7 @@ FnTableEntry *create_fn(AstNode *proto_node) { AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; - GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ? - GlobalLinkageIdStrong : GlobalLinkageIdInternal; - FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage); + FnTableEntry *fn_entry = create_fn_raw(inline_value); fn_entry->proto_node = proto_node; fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : @@ -2572,7 +2601,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { add_node_error(g, param_node, buf_sprintf("missing parameter name")); } } - } else if (fn_table_entry->linkage != GlobalLinkageIdInternal) { + } else { g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); } @@ -2580,6 +2609,15 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); + if (fn_proto->section_expr != nullptr) { + if (fn_table_entry->body_node == nullptr) { + add_node_error(g, fn_proto->section_expr, + buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_table_entry->symbol_name))); + } else { + analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name); + } + } + if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { tld_fn->base.resolution = TldResolutionInvalid; return; @@ -2594,15 +2632,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { { if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { g->main_fn = fn_table_entry; - - if (tld_fn->base.visib_mod != VisibModExport) { - TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); - TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; - if (actual_return_type != err_void) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("expected return type of main to be '%%void', instead is '%s'", - buf_ptr(&actual_return_type->name))); - } + TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); + TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; + if (actual_return_type != err_void) { + add_node_error(g, fn_proto->return_type, + buf_sprintf("expected return type of main to be '%%void', instead is '%s'", + buf_ptr(&actual_return_type->name))); } } else if ((import->package == g->panic_package || g->have_pub_panic) && buf_eql_str(&fn_table_entry->symbol_name, "panic")) @@ -2613,7 +2648,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } } else if (source_node->type == NodeTypeTestDecl) { - FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); + FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); @@ -2640,20 +2675,6 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { - if (tld->visib_mod == VisibModExport) { - g->resolve_queue.append(tld); - } - - if (tld->visib_mod == VisibModExport) { - auto entry = g->exported_symbol_names.put_unique(tld->name, tld); - if (entry) { - Tld *other_tld = entry->value; - ErrorMsg *msg = add_node_error(g, tld->source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_tld->source_node, buf_sprintf("other symbol is here")); - } - } - { auto entry = decls_scope->decl_table.put_unique(tld->name, tld); if (entry) { @@ -2729,7 +2750,6 @@ static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_s g->resolve_queue.append(&tld_comptime->base); } - void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope) { @@ -2985,7 +3005,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; bool is_const = var_decl->is_const; - bool is_export = (tld_var->base.visib_mod == VisibModExport); bool is_extern = var_decl->is_extern; TypeTableEntry *explicit_type = nullptr; @@ -2994,20 +3013,13 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { explicit_type = validate_var_type(g, var_decl->type, proposed_type); } - if (is_export && is_extern) { - add_node_error(g, source_node, buf_sprintf("variable is both export and extern")); - } - VarLinkage linkage; - if (is_export) { - linkage = VarLinkageExport; - } else if (is_extern) { + if (is_extern) { linkage = VarLinkageExternal; } else { linkage = VarLinkageInternal; } - IrInstruction *init_value = nullptr; // TODO more validation for types that can't be used for export/extern variables @@ -3056,6 +3068,15 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } } + if (var_decl->section_expr != nullptr) { + if (var_decl->is_extern) { + add_node_error(g, var_decl->section_expr, + buf_sprintf("cannot set section of external variable '%s'", buf_ptr(var_decl->symbol))); + } else if (!analyze_const_string(g, tld_var->base.parent_scope, var_decl->section_expr, &tld_var->section_name)) { + tld_var->section_name = nullptr; + } + } + g->global_vars.append(tld_var); } @@ -3724,8 +3745,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a Buf *proto_name = proto_node->data.fn_proto.name; bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub); + bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified || + proto_node->data.fn_proto.cc == CallingConventionCold); - if (is_pub) { + if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; g->windows_subsystem_windows = false; @@ -3733,28 +3756,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") && - g->libc_link_lib != nullptr) - { - g->have_c_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "WinMain") && - g->zig_target.os == ZigLLVM_Win32) - { - g->have_winmain = true; - g->windows_subsystem_windows = true; - g->windows_subsystem_console = false; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && - buf_eql_str(proto_name, "WinMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) - { - g->have_winmain_crt_startup = true; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && - buf_eql_str(proto_name, "DllMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) - { - g->have_dllmain_crt_startup = true; } - } } @@ -5445,3 +5447,4 @@ uint32_t type_ptr_hash(const TypeTableEntry *ptr) { bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { return a == b; } + diff --git a/src/analyze.hpp b/src/analyze.hpp index e12c4cda44..0e727568c6 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -182,4 +182,6 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); TypeTableEntry *get_align_amt_type(CodeGen *g); PackageTableEntry *new_anonymous_package(void); +Buf *const_value_to_buffer(ConstExprValue *const_val); + #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index d6a23e5f85..fc01c79ca6 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -78,7 +78,6 @@ static const char *visib_mod_string(VisibMod mod) { switch (mod) { case VisibModPub: return "pub "; case VisibModPrivate: return ""; - case VisibModExport: return "export "; } zig_unreachable(); } @@ -440,6 +439,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } } fprintf(ar->f, ")"); + if (node->data.fn_proto.align_expr) { + fprintf(ar->f, " align("); + render_node_grouped(ar, node->data.fn_proto.align_expr); + fprintf(ar->f, ")"); + } + if (node->data.fn_proto.section_expr) { + fprintf(ar->f, " section("); + render_node_grouped(ar, node->data.fn_proto.section_expr); + fprintf(ar->f, ")"); + } AstNode *return_type_node = node->data.fn_proto.return_type; if (return_type_node != nullptr) { @@ -526,6 +535,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ": "); render_node_grouped(ar, node->data.variable_declaration.type); } + if (node->data.variable_declaration.align_expr) { + fprintf(ar->f, "align("); + render_node_grouped(ar, node->data.variable_declaration.align_expr); + fprintf(ar->f, ") "); + } + if (node->data.variable_declaration.section_expr) { + fprintf(ar->f, "section("); + render_node_grouped(ar, node->data.variable_declaration.section_expr); + fprintf(ar->f, ") "); + } if (node->data.variable_declaration.expr) { fprintf(ar->f, " = "); render_node_grouped(ar, node->data.variable_declaration.expr); diff --git a/src/codegen.cpp b/src/codegen.cpp index 44b3df3526..5be26eb445 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -391,24 +391,51 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { } } +static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { + switch (id) { + case GlobalLinkageIdInternal: + return LLVMInternalLinkage; + case GlobalLinkageIdStrong: + return LLVMExternalLinkage; + case GlobalLinkageIdWeak: + return LLVMWeakODRLinkage; + case GlobalLinkageIdLinkOnce: + return LLVMLinkOnceODRLinkage; + } + zig_unreachable(); +} + static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_table_entry->llvm_value) return fn_table_entry->llvm_value; - bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal); - Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage); + Buf *unmangled_name = &fn_table_entry->symbol_name; + Buf *symbol_name; + GlobalLinkageId linkage; + if (fn_table_entry->body_node == nullptr) { + symbol_name = unmangled_name; + linkage = GlobalLinkageIdStrong; + } else if (fn_table_entry->export_list.length == 0) { + symbol_name = get_mangled_name(g, unmangled_name, false); + linkage = GlobalLinkageIdInternal; + } else { + FnExport *fn_export = &fn_table_entry->export_list.items[0]; + symbol_name = &fn_export->name; + linkage = fn_export->linkage; + } + bool external_linkage = linkage != GlobalLinkageIdInternal; if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage && g->zig_target.arch.arch == ZigLLVM_x86) { - // prevent name mangling + // prevent llvm name mangling symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name)); } TypeTableEntry *fn_type = fn_table_entry->type_entry; LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; - if (external_linkage && fn_table_entry->body_node == nullptr) { + if (fn_table_entry->body_node == nullptr) { LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); if (existing_llvm_fn) { fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); @@ -418,6 +445,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } else { fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); + + for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) { + FnExport *fn_export = &fn_table_entry->export_list.items[i]; + LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value), + fn_table_entry->llvm_value, buf_ptr(&fn_export->name)); + } } fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value); @@ -445,20 +478,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } - switch (fn_table_entry->linkage) { - case GlobalLinkageIdInternal: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage); - LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); - break; - case GlobalLinkageIdStrong: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); - break; - case GlobalLinkageIdWeak: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); - break; - case GlobalLinkageIdLinkOnce: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); - break; + LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage)); + + if (linkage == GlobalLinkageIdInternal) { + LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); } if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { @@ -565,7 +588,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { bool is_definition = fn_table_entry->body_node != nullptr; unsigned flags = 0; bool is_optimized = g->build_mode != BuildModeDebug; - bool is_internal_linkage = (fn_table_entry->linkage == GlobalLinkageIdInternal); + bool is_internal_linkage = (fn_table_entry->body_node != nullptr && + fn_table_entry->export_list.length == 0); ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, @@ -3487,8 +3511,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCheckStatementIsVoid: case IrInstructionIdTypeName: case IrInstructionIdCanImplicitCast: - case IrInstructionIdSetGlobalSection: - case IrInstructionIdSetGlobalLinkage: case IrInstructionIdDeclRef: case IrInstructionIdSwitchVar: case IrInstructionIdOffsetOf: @@ -3499,6 +3521,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSetAlignStack: case IrInstructionIdArgType: case IrInstructionIdTagType: + case IrInstructionIdExport: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -4969,8 +4992,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); - create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); - create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); @@ -4995,6 +5016,8 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); + create_builtin_fn(g, BuiltinFnIdExport, "export", 2); + create_builtin_fn(g, BuiltinFnIdExportWithLinkage, "exportWithLinkage", 3); } static const char *bool_to_str(bool b) { @@ -5433,6 +5456,27 @@ static void gen_root_source(CodeGen *g) { assert(g->root_out_name); assert(g->out_type != OutTypeUnknown); + { + // Zig has lazy top level definitions. Here we semantically analyze the panic function. + ImportTableEntry *import_with_panic; + if (g->have_pub_panic) { + import_with_panic = g->root_import; + } else { + g->panic_package = create_panic_pkg(g); + import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); + } + scan_import(g, import_with_panic); + Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); + assert(panic_tld != nullptr); + resolve_top_level_decl(g, panic_tld, false, nullptr); + } + + + if (!g->error_during_imports) { + semantic_analyze(g); + } + report_errors_and_maybe_exit(g); + if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS && !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) @@ -5442,20 +5486,6 @@ static void gen_root_source(CodeGen *g) { if (g->zig_target.os == ZigLLVM_Win32 && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib) { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } - ImportTableEntry *import_with_panic; - if (g->have_pub_panic) { - import_with_panic = g->root_import; - } else { - g->panic_package = create_panic_pkg(g); - import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); - } - // Zig has lazy top level definitions. Here we semantically analyze the panic function. - { - scan_import(g, import_with_panic); - Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); - assert(panic_tld != nullptr); - resolve_top_level_decl(g, panic_tld, false, nullptr); - } if (!g->error_during_imports) { semantic_analyze(g); @@ -5682,7 +5712,7 @@ static void gen_h_file(CodeGen *g) { for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); - if (fn_table_entry->linkage == GlobalLinkageIdInternal) + if (fn_table_entry->export_list.length == 0) continue; FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; diff --git a/src/ir.cpp b/src/ir.cpp index ce7d8dcedd..81b64a318d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -207,6 +207,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { return IrInstructionIdDeclVar; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { + return IrInstructionIdExport; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) { return IrInstructionIdLoadPtr; } @@ -523,14 +527,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast return IrInstructionIdCanImplicitCast; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) { - return IrInstructionIdSetGlobalSection; -} - -static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) { - return IrInstructionIdSetGlobalLinkage; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { return IrInstructionIdDeclRef; } @@ -1205,6 +1201,24 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_ return new_instruction; } +static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *name, IrInstruction *target, IrInstruction *linkage) +{ + IrInstructionExport *export_instruction = ir_build_instruction( + irb, scope, source_node); + export_instruction->base.value.special = ConstValSpecialStatic; + export_instruction->base.value.type = irb->codegen->builtin_types.entry_void; + export_instruction->name = name; + export_instruction->target = target; + export_instruction->linkage = linkage; + + ir_ref_instruction(name, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + if (linkage) ir_ref_instruction(linkage, irb->current_basic_block); + + return &export_instruction->base; +} + static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; @@ -2159,32 +2173,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A return &instruction->base; } -static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, IrInstruction *value) -{ - IrInstructionSetGlobalSection *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->tld = tld; - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_set_global_linkage(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, IrInstruction *value) -{ - IrInstructionSetGlobalLinkage *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->tld = tld; - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { @@ -2396,6 +2384,21 @@ static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instr return nullptr; } +static IrInstruction *ir_instruction_export_get_dep(IrInstructionExport *instruction, size_t index) { + if (index < 1) return instruction->name; + index -= 1; + + if (index < 1) return instruction->target; + index -= 1; + + if (instruction->linkage != nullptr) { + if (index < 1) return instruction->linkage; + index -= 1; + } + + return nullptr; +} + static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) { switch (index) { case 0: return instruction->ptr; @@ -2979,20 +2982,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp } } -static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGlobalSection *instruction, size_t index) { - switch (index) { - case 0: return instruction->value; - default: return nullptr; - } -} - -static IrInstruction *ir_instruction_setgloballinkage_get_dep(IrInstructionSetGlobalLinkage *instruction, size_t index) { - switch (index) { - case 0: return instruction->value; - default: return nullptr; - } -} - static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { return nullptr; } @@ -3106,6 +3095,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_binop_get_dep((IrInstructionBinOp *) instruction, index); case IrInstructionIdDeclVar: return ir_instruction_declvar_get_dep((IrInstructionDeclVar *) instruction, index); + case IrInstructionIdExport: + return ir_instruction_export_get_dep((IrInstructionExport *) instruction, index); case IrInstructionIdLoadPtr: return ir_instruction_loadptr_get_dep((IrInstructionLoadPtr *) instruction, index); case IrInstructionIdStorePtr: @@ -3264,10 +3255,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index); case IrInstructionIdCanImplicitCast: return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index); - case IrInstructionIdSetGlobalSection: - return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); - case IrInstructionIdSetGlobalLinkage: - return ir_instruction_setgloballinkage_get_dep((IrInstructionSetGlobalLinkage *) instruction, index); case IrInstructionIdDeclRef: return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); case IrInstructionIdPanic: @@ -4528,39 +4515,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); } - case BuiltinFnIdSetGlobalSection: - case BuiltinFnIdSetGlobalLinkage: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - if (arg0_node->type != NodeTypeSymbol) { - add_node_error(irb->codegen, arg0_node, buf_sprintf("expected identifier")); - return irb->codegen->invalid_instruction; - } - Buf *variable_name = arg0_node->data.symbol_expr.symbol; - Tld *tld = find_decl(irb->codegen, scope, variable_name); - if (!tld) { - add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", - buf_ptr(variable_name))); - return irb->codegen->invalid_instruction; - } - if (tld->id != TldIdVar && tld->id != TldIdFn) { - add_node_error(irb->codegen, node, buf_sprintf("'%s' must be global variable or function", - buf_ptr(variable_name))); - return irb->codegen->invalid_instruction; - } - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - if (builtin_fn->id == BuiltinFnIdSetGlobalSection) { - return ir_build_set_global_section(irb, scope, node, tld, arg1_value); - } else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) { - return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value); - } else { - zig_unreachable(); - } - } case BuiltinFnIdPanic: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4784,6 +4738,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); } + case BuiltinFnIdExport: + case BuiltinFnIdExportWithLinkage: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *arg2_value; + if (builtin_fn->id == BuiltinFnIdExportWithLinkage) { + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; + } else { + arg2_value = nullptr; + } + + return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); + } } zig_unreachable(); } @@ -5106,6 +5085,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return align_value; } + if (variable_declaration->section_expr != nullptr) { + add_node_error(irb->codegen, variable_declaration->section_expr, + buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); + } + IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); if (init_value == irb->codegen->invalid_instruction) return init_value; @@ -6355,6 +6339,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSwitchRange: case NodeTypeStructField: case NodeTypeLabel: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeErrorValueDecl: + case NodeTypeTestDecl: zig_unreachable(); case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); @@ -6436,14 +6424,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); case NodeTypeFnProto: return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); - case NodeTypeFnDef: - zig_panic("TODO IR gen NodeTypeFnDef"); - case NodeTypeFnDecl: - zig_panic("TODO IR gen NodeTypeFnDecl"); - case NodeTypeErrorValueDecl: - zig_panic("TODO IR gen NodeTypeErrorValueDecl"); - case NodeTypeTestDecl: - zig_panic("TODO IR gen NodeTypeTestDecl"); } zig_unreachable(); } @@ -10481,6 +10461,194 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { + IrInstruction *name = instruction->name->other; + Buf *symbol_name = ir_resolve_str(ira, name); + if (symbol_name == nullptr) { + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *target = instruction->target->other; + if (type_is_invalid(target->value.type)) { + return ira->codegen->builtin_types.entry_invalid; + } + + GlobalLinkageId global_linkage_id = GlobalLinkageIdStrong; + if (instruction->linkage != nullptr) { + IrInstruction *linkage_value = instruction->linkage->other; + if (!ir_resolve_global_linkage(ira, linkage_value, &global_linkage_id)) { + return ira->codegen->builtin_types.entry_invalid; + } + } + + auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, instruction->base.source_node); + if (entry) { + AstNode *other_export_node = entry->value; + ErrorMsg *msg = ir_add_error(ira, &instruction->base, + buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); + add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here")); + } + + switch (target->value.type->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + case TypeTableEntryIdUnreachable: + zig_unreachable(); + case TypeTableEntryIdFn: { + FnTableEntry *fn_entry = target->value.data.x_fn.fn_entry; + CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; + switch (cc) { + case CallingConventionUnspecified: { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported function must specify calling convention")); + add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); + } break; + case CallingConventionC: + if (buf_eql_str(symbol_name, "main") && ira->codegen->libc_link_lib != nullptr) { + ira->codegen->have_c_main = true; + ira->codegen->windows_subsystem_windows = false; + ira->codegen->windows_subsystem_console = true; + } else if (buf_eql_str(symbol_name, "WinMain") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_winmain = true; + ira->codegen->windows_subsystem_windows = true; + ira->codegen->windows_subsystem_console = false; + } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_winmain_crt_startup = true; + } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_dllmain_crt_startup = true; + } + // fallthrough + case CallingConventionNaked: + case CallingConventionCold: + case CallingConventionStdcall: { + FnExport *fn_export = fn_entry->export_list.add_one(); + memset(fn_export, 0, sizeof(FnExport)); + buf_init_from_buf(&fn_export->name, symbol_name); + fn_export->linkage = global_linkage_id; + fn_export->source_node = instruction->base.source_node; + } break; + } + } break; + case TypeTableEntryIdStruct: + if (is_slice(target->value.type)) { + ir_add_error(ira, target, + buf_sprintf("unable to export value of type '%s'", buf_ptr(&target->value.type->name))); + } else if (target->value.type->data.structure.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported struct value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdUnion: + if (target->value.type->data.unionation.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported union value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdEnum: + if (target->value.type->data.enumeration.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported enum value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdMetaType: { + TypeTableEntry *type_value = target->value.data.x_type; + switch (type_value->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + zig_unreachable(); + case TypeTableEntryIdStruct: + if (is_slice(type_value)) { + ir_add_error(ira, target, + buf_sprintf("unable to export type '%s'", buf_ptr(&type_value->name))); + } else if (type_value->data.structure.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported struct must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.structure.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdUnion: + if (type_value->data.unionation.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported union must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.unionation.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdEnum: + if (type_value->data.enumeration.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported enum must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.enumeration.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdFn: { + if (type_value->data.fn.fn_type_id.cc == CallingConventionUnspecified) { + ir_add_error(ira, target, + buf_sprintf("exported function type must specify calling convention")); + } + } break; + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdBool: + break; + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: + ir_add_error(ira, target, + buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); + break; + } + } break; + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: + ir_add_error(ira, target, + buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name))); + break; + } + + ir_build_const_from(ira, &instruction->base); + return ira->codegen->builtin_types.entry_void; +} + static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) { @@ -12399,102 +12567,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, return ira->codegen->builtin_types.entry_type; } -static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira, - IrInstructionSetGlobalSection *instruction) -{ - Tld *tld = instruction->tld; - IrInstruction *section_value = instruction->value->other; - - resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->builtin_types.entry_invalid; - - Buf *section_name = ir_resolve_str(ira, section_value); - if (!section_name) - return ira->codegen->builtin_types.entry_invalid; - - AstNode **set_global_section_node; - Buf **section_name_ptr; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - set_global_section_node = &tld_var->set_global_section_node; - section_name_ptr = &tld_var->section_name; - - if (tld_var->var->linkage == VarLinkageExternal) { - ErrorMsg *msg = ir_add_error(ira, &instruction->base, - buf_sprintf("cannot set section of external variable '%s'", buf_ptr(&tld_var->var->name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (tld->id == TldIdFn) { - TldFn *tld_fn = (TldFn *)tld; - FnTableEntry *fn_entry = tld_fn->fn_entry; - set_global_section_node = &fn_entry->set_global_section_node; - section_name_ptr = &fn_entry->section_name; - - if (fn_entry->def_scope == nullptr) { - ErrorMsg *msg = ir_add_error(ira, &instruction->base, - buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_entry->symbol_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->builtin_types.entry_invalid; - } - } else { - // error is caught in pass1 IR gen - zig_unreachable(); - } - - AstNode *source_node = instruction->base.source_node; - if (*set_global_section_node) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("section set twice")); - add_error_note(ira->codegen, msg, *set_global_section_node, buf_sprintf("first set here")); - return ira->codegen->builtin_types.entry_invalid; - } - *set_global_section_node = source_node; - *section_name_ptr = section_name; - - ir_build_const_from(ira, &instruction->base); - return ira->codegen->builtin_types.entry_void; -} - -static TypeTableEntry *ir_analyze_instruction_set_global_linkage(IrAnalyze *ira, - IrInstructionSetGlobalLinkage *instruction) -{ - Tld *tld = instruction->tld; - IrInstruction *linkage_value = instruction->value->other; - - GlobalLinkageId linkage_scalar; - if (!ir_resolve_global_linkage(ira, linkage_value, &linkage_scalar)) - return ira->codegen->builtin_types.entry_invalid; - - AstNode **set_global_linkage_node; - GlobalLinkageId *dest_linkage_ptr; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - set_global_linkage_node = &tld_var->set_global_linkage_node; - dest_linkage_ptr = &tld_var->linkage; - } else if (tld->id == TldIdFn) { - TldFn *tld_fn = (TldFn *)tld; - FnTableEntry *fn_entry = tld_fn->fn_entry; - set_global_linkage_node = &fn_entry->set_global_linkage_node; - dest_linkage_ptr = &fn_entry->linkage; - } else { - // error is caught in pass1 IR gen - zig_unreachable(); - } - - AstNode *source_node = instruction->base.source_node; - if (*set_global_linkage_node) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("linkage set twice")); - add_error_note(ira->codegen, msg, *set_global_linkage_node, buf_sprintf("first set here")); - return ira->codegen->builtin_types.entry_invalid; - } - *set_global_linkage_node = source_node; - *dest_linkage_ptr = linkage_scalar; - - ir_build_const_from(ira, &instruction->base); - return ira->codegen->builtin_types.entry_void; -} - static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, IrInstructionSetDebugSafety *set_debug_safety_instruction) { @@ -16165,10 +16237,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); case IrInstructionIdPtrTypeChild: return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); - case IrInstructionIdSetGlobalSection: - return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction); - case IrInstructionIdSetGlobalLinkage: - return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); case IrInstructionIdSetDebugSafety: return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); case IrInstructionIdSetFloatMode: @@ -16311,6 +16379,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); case IrInstructionIdTagType: return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); + case IrInstructionIdExport: + return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); } zig_unreachable(); } @@ -16418,12 +16488,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free case IrInstructionIdCheckSwitchProngs: case IrInstructionIdCheckStatementIsVoid: - case IrInstructionIdSetGlobalSection: - case IrInstructionIdSetGlobalLinkage: case IrInstructionIdPanic: case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrTypeOf: case IrInstructionIdSetAlignStack: + case IrInstructionIdExport: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b6a7c32dfc..f5aba2a45d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -899,19 +899,6 @@ static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instructi ir_print_other_instruction(irp, instruction->child_type); } -static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSection *instruction) { - fprintf(irp->f, "@setGlobalSection(%s,", buf_ptr(instruction->tld->name)); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_set_global_linkage(IrPrint *irp, IrInstructionSetGlobalLinkage *instruction) { - fprintf(irp->f, "@setGlobalLinkage(%s,", buf_ptr(instruction->tld->name)); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - - static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; const char *const_str = instruction->lval.is_const ? "const " : ""; @@ -991,6 +978,24 @@ static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instructi fprintf(irp->f, ")"); } +static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { + if (instruction->linkage == nullptr) { + fprintf(irp->f, "@export("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); + } else { + fprintf(irp->f, "@exportWithLinkage("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->linkage); + fprintf(irp->f, ")"); + } +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); @@ -1267,12 +1272,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrTypeOf: ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction); break; - case IrInstructionIdSetGlobalSection: - ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); - break; - case IrInstructionIdSetGlobalLinkage: - ir_print_set_global_linkage(irp, (IrInstructionSetGlobalLinkage *)instruction); - break; case IrInstructionIdDeclRef: ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); break; @@ -1306,6 +1305,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTagType: ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); break; + case IrInstructionIdExport: + ir_print_export(irp, (IrInstructionExport *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/parser.cpp b/src/parser.cpp index 26ca7da31a..07c221e287 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1600,6 +1600,14 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to next_token = &pc->tokens->at(*token_index); } + if (next_token->id == TokenIdKeywordSection) { + *token_index += 1; + ast_eat_token(pc, token_index, TokenIdLParen); + node->data.variable_declaration.section_expr = ast_parse_expression(pc, token_index, true); + ast_eat_token(pc, token_index, TokenIdRParen); + next_token = &pc->tokens->at(*token_index); + } + if (next_token->id == TokenIdEq) { *token_index += 1; node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); @@ -2144,7 +2152,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { /* Block = "{" many(Statement) option(Expression) "}" -Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" +Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl */ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { Token *last_token = &pc->tokens->at(*token_index); @@ -2205,7 +2213,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand } /* -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) */ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); @@ -2259,6 +2267,14 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m ast_eat_token(pc, token_index, TokenIdRParen); next_token = &pc->tokens->at(*token_index); } + if (next_token->id == TokenIdKeywordSection) { + *token_index += 1; + ast_eat_token(pc, token_index, TokenIdLParen); + + node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); + ast_eat_token(pc, token_index, TokenIdRParen); + next_token = &pc->tokens->at(*token_index); + } if (next_token->id == TokenIdArrow) { *token_index += 1; node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false); @@ -2447,9 +2463,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, if (visib_tok->id == TokenIdKeywordPub) { *token_index += 1; visib_mod = VisibModPub; - } else if (visib_tok->id == TokenIdKeywordExport) { - *token_index += 1; - visib_mod = VisibModExport; } else { visib_mod = VisibModPrivate; } @@ -2580,9 +2593,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig if (visib_tok->id == TokenIdKeywordPub) { *token_index += 1; visib_mod = VisibModPub; - } else if (visib_tok->id == TokenIdKeywordExport) { - *token_index += 1; - visib_mod = VisibModExport; } else { visib_mod = VisibModPrivate; } @@ -2669,6 +2679,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.fn_proto.return_type, visit, context); visit_node_list(&node->data.fn_proto.params, visit, context); visit_field(&node->data.fn_proto.align_expr, visit, context); + visit_field(&node->data.fn_proto.section_expr, visit, context); break; case NodeTypeFnDef: visit_field(&node->data.fn_def.fn_proto, visit, context); @@ -2696,6 +2707,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.variable_declaration.type, visit, context); visit_field(&node->data.variable_declaration.expr, visit, context); visit_field(&node->data.variable_declaration.align_expr, visit, context); + visit_field(&node->data.variable_declaration.section_expr, visit, context); break; case NodeTypeErrorValueDecl: // none diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 77d74c52ee..a14f709744 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -119,7 +119,6 @@ static const struct ZigKeyword zig_keywords[] = { {"else", TokenIdKeywordElse}, {"enum", TokenIdKeywordEnum}, {"error", TokenIdKeywordError}, - {"export", TokenIdKeywordExport}, {"extern", TokenIdKeywordExtern}, {"false", TokenIdKeywordFalse}, {"fn", TokenIdKeywordFn}, @@ -134,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = { {"packed", TokenIdKeywordPacked}, {"pub", TokenIdKeywordPub}, {"return", TokenIdKeywordReturn}, + {"section", TokenIdKeywordSection}, {"stdcallcc", TokenIdKeywordStdcallCC}, {"struct", TokenIdKeywordStruct}, {"switch", TokenIdKeywordSwitch}, @@ -1518,7 +1518,6 @@ const char * token_name(TokenId id) { case TokenIdKeywordElse: return "else"; case TokenIdKeywordEnum: return "enum"; case TokenIdKeywordError: return "error"; - case TokenIdKeywordExport: return "export"; case TokenIdKeywordExtern: return "extern"; case TokenIdKeywordFalse: return "false"; case TokenIdKeywordFn: return "fn"; @@ -1533,6 +1532,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordPacked: return "packed"; case TokenIdKeywordPub: return "pub"; case TokenIdKeywordReturn: return "return"; + case TokenIdKeywordSection: return "section"; case TokenIdKeywordStdcallCC: return "stdcallcc"; case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordSwitch: return "switch"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index bcad977864..b0444b9c3b 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -47,6 +47,7 @@ enum TokenId { TokenIdFloatLiteral, TokenIdIntLiteral, TokenIdKeywordAlign, + TokenIdKeywordSection, TokenIdKeywordAnd, TokenIdKeywordAsm, TokenIdKeywordBreak, @@ -58,7 +59,6 @@ enum TokenId { TokenIdKeywordElse, TokenIdKeywordEnum, TokenIdKeywordError, - TokenIdKeywordExport, TokenIdKeywordExtern, TokenIdKeywordFalse, TokenIdKeywordFn, diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 4575d4ee56..77afc38a51 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -73,7 +73,6 @@ struct Context { ImportTableEntry *import; ZigList *errors; VisibMod visib_mod; - VisibMod export_visib_mod; AstNode *root; HashMap decl_table; HashMap macro_table; @@ -3251,7 +3250,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { StorageClass sc = fn_decl->getStorageClass(); if (sc == SC_None) { - proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; + // TODO add export decl + proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_Extern || sc == SC_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_PrivateExtern) { @@ -4274,10 +4274,8 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { c->visib_mod = VisibModPub; - c->export_visib_mod = VisibModPub; } else { c->visib_mod = VisibModPub; - c->export_visib_mod = VisibModExport; } c->decl_table.init(8); c->macro_table.init(8); diff --git a/std/debug.zig b/std/debug.zig index a6229f88da..1035948e3e 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -96,8 +96,6 @@ const WHITE = "\x1b[37;1m"; const DIM = "\x1b[2m"; const RESET = "\x1b[0m"; -pub var user_main_fn: ?fn() -> %void = null; - error PathNotFound; error InvalidDebugInfo; diff --git a/std/elf.zig b/std/elf.zig index f7be236d15..2c5b10b3f2 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -188,39 +188,39 @@ pub const Elf = struct { if (elf.is_64) { if (sh_entry_size != 64) return error.InvalidFormat; - for (elf.section_headers) |*section| { - section.name = %return in.readInt(elf.endian, u32); - section.sh_type = %return in.readInt(elf.endian, u32); - section.flags = %return in.readInt(elf.endian, u64); - section.addr = %return in.readInt(elf.endian, u64); - section.offset = %return in.readInt(elf.endian, u64); - section.size = %return in.readInt(elf.endian, u64); - section.link = %return in.readInt(elf.endian, u32); - section.info = %return in.readInt(elf.endian, u32); - section.addr_align = %return in.readInt(elf.endian, u64); - section.ent_size = %return in.readInt(elf.endian, u64); + for (elf.section_headers) |*elf_section| { + elf_section.name = %return in.readInt(elf.endian, u32); + elf_section.sh_type = %return in.readInt(elf.endian, u32); + elf_section.flags = %return in.readInt(elf.endian, u64); + elf_section.addr = %return in.readInt(elf.endian, u64); + elf_section.offset = %return in.readInt(elf.endian, u64); + elf_section.size = %return in.readInt(elf.endian, u64); + elf_section.link = %return in.readInt(elf.endian, u32); + elf_section.info = %return in.readInt(elf.endian, u32); + elf_section.addr_align = %return in.readInt(elf.endian, u64); + elf_section.ent_size = %return in.readInt(elf.endian, u64); } } else { if (sh_entry_size != 40) return error.InvalidFormat; - for (elf.section_headers) |*section| { + for (elf.section_headers) |*elf_section| { // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? - section.name = %return in.readInt(elf.endian, u32); - section.sh_type = %return in.readInt(elf.endian, u32); - section.flags = u64(%return in.readInt(elf.endian, u32)); - section.addr = u64(%return in.readInt(elf.endian, u32)); - section.offset = u64(%return in.readInt(elf.endian, u32)); - section.size = u64(%return in.readInt(elf.endian, u32)); - section.link = %return in.readInt(elf.endian, u32); - section.info = %return in.readInt(elf.endian, u32); - section.addr_align = u64(%return in.readInt(elf.endian, u32)); - section.ent_size = u64(%return in.readInt(elf.endian, u32)); + elf_section.name = %return in.readInt(elf.endian, u32); + elf_section.sh_type = %return in.readInt(elf.endian, u32); + elf_section.flags = u64(%return in.readInt(elf.endian, u32)); + elf_section.addr = u64(%return in.readInt(elf.endian, u32)); + elf_section.offset = u64(%return in.readInt(elf.endian, u32)); + elf_section.size = u64(%return in.readInt(elf.endian, u32)); + elf_section.link = %return in.readInt(elf.endian, u32); + elf_section.info = %return in.readInt(elf.endian, u32); + elf_section.addr_align = u64(%return in.readInt(elf.endian, u32)); + elf_section.ent_size = u64(%return in.readInt(elf.endian, u32)); } } - for (elf.section_headers) |*section| { - if (section.sh_type != SHT_NOBITS) { - const file_end_offset = %return math.add(u64, section.offset, section.size); + for (elf.section_headers) |*elf_section| { + if (elf_section.sh_type != SHT_NOBITS) { + const file_end_offset = %return math.add(u64, elf_section.offset, elf_section.size); if (stream_end < file_end_offset) return error.InvalidFormat; } } @@ -243,10 +243,10 @@ pub const Elf = struct { var file_stream = io.FileInStream.init(elf.in_file); const in = &file_stream.stream; - for (elf.section_headers) |*section| { - if (section.sh_type == SHT_NULL) continue; + for (elf.section_headers) |*elf_section| { + if (elf_section.sh_type == SHT_NULL) continue; - const name_offset = elf.string_section.offset + section.name; + const name_offset = elf.string_section.offset + elf_section.name; %return elf.in_file.seekTo(name_offset); for (name) |expected_c| { @@ -256,7 +256,7 @@ pub const Elf = struct { { const null_byte = %return in.readByte(); - if (null_byte == 0) return section; + if (null_byte == 0) return elf_section; } next_section: @@ -265,7 +265,7 @@ pub const Elf = struct { return null; } - pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void { - %return elf.in_file.seekTo(section.offset); + pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) -> %void { + %return elf.in_file.seekTo(elf_section.offset); } }; diff --git a/std/mem.zig b/std/mem.zig index 10d2221f9a..e9883afd39 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -4,6 +4,7 @@ const math = @import("math/index.zig"); const builtin = @import("builtin"); pub const Cmp = math.Cmp; +error OutOfMemory; pub const Allocator = struct { /// Allocate byte_count bytes and return them in a slice, with the diff --git a/std/os/linux.zig b/std/os/linux.zig index 5951f9d7bc..4ba4db603f 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -651,28 +651,6 @@ pub const iovec = extern struct { iov_len: usize, }; -// -//const IF_NAMESIZE = 16; -// -//export struct ifreq { -// ifrn_name: [IF_NAMESIZE]u8, -// union { -// ifru_addr: sockaddr, -// ifru_dstaddr: sockaddr, -// ifru_broadaddr: sockaddr, -// ifru_netmask: sockaddr, -// ifru_hwaddr: sockaddr, -// ifru_flags: i16, -// ifru_ivalue: i32, -// ifru_mtu: i32, -// ifru_map: ifmap, -// ifru_slave: [IF_NAMESIZE]u8, -// ifru_newname: [IF_NAMESIZE]u8, -// ifru_data: &u8, -// } ifr_ifru; -//} -// - pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)) } diff --git a/std/os/linux_i386.zig b/std/os/linux_i386.zig index 215670e3a9..ed49e33c2b 100644 --- a/std/os/linux_i386.zig +++ b/std/os/linux_i386.zig @@ -502,13 +502,3 @@ pub nakedcc fn restore_rt() { : [number] "{eax}" (usize(SYS_rt_sigreturn)) : "rcx", "r11") } - -export struct msghdr { - msg_name: &u8, - msg_namelen: socklen_t, - msg_iov: &iovec, - msg_iovlen: i32, - msg_control: &u8, - msg_controllen: socklen_t, - msg_flags: i32, -} diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 99bea09726..ee63467305 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -5,20 +5,19 @@ const root = @import("@root"); const std = @import("std"); const builtin = @import("builtin"); -const is_windows = builtin.os == builtin.Os.windows; -const want_main_symbol = builtin.link_libc; -const want_start_symbol = !want_main_symbol and !is_windows; -const want_WinMainCRTStartup = is_windows and !builtin.link_libc; - var argc_ptr: &usize = undefined; - -export nakedcc fn _start() -> noreturn { - if (!want_start_symbol) { - @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal); - unreachable; +comptime { + if (builtin.link_libc) { + @export("main", main); + } else if (builtin.os == builtin.Os.windows) { + @export("WinMainCRTStartup", WinMainCRTStartup); + } else { + @export("_start", _start); } +} +nakedcc fn _start() -> noreturn { switch (builtin.arch) { builtin.Arch.x86_64 => { argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); @@ -33,14 +32,9 @@ export nakedcc fn _start() -> noreturn { @noInlineCall(posixCallMainAndExit); } -export fn WinMainCRTStartup() -> noreturn { - if (!want_WinMainCRTStartup) { - @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal); - unreachable; - } +extern fn WinMainCRTStartup() -> noreturn { @setAlignStack(16); - std.debug.user_main_fn = root.main; root.main() %% std.os.windows.ExitProcess(1); std.os.windows.ExitProcess(0); } @@ -60,17 +54,10 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { while (envp[env_count] != null) : (env_count += 1) {} std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; - std.debug.user_main_fn = root.main; - return root.main(); } -export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { - if (!want_main_symbol) { - @setGlobalLinkage(main, builtin.GlobalLinkage.Internal); - unreachable; - } - +extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { callMain(usize(c_argc), c_argv, c_envp) %% return 1; return 0; } diff --git a/std/special/bootstrap_lib.zig b/std/special/bootstrap_lib.zig index 7412d64fa6..3c7789f30a 100644 --- a/std/special/bootstrap_lib.zig +++ b/std/special/bootstrap_lib.zig @@ -2,7 +2,11 @@ const std = @import("std"); -export stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, +comptime { + @export("_DllMainCRTStartup", _DllMainCRTStartup); +} + +stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL { return std.os.windows.TRUE; diff --git a/std/special/builtin.zig b/std/special/builtin.zig index 51e6646574..9ace9b46ca 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -13,10 +13,24 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } +comptime { + @export("memset", memset); + @export("memcpy", memcpy); + @export("fmodf", fmodf); + @export("fmod", fmod); + @export("floorf", floorf); + @export("ceilf", ceilf); + @export("floor", floor); + @export("ceil", ceil); + if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { + @export("__stack_chk_fail", __stack_chk_fail); + } +} + // Note that memset does not return `dest`, like the libc API. // The semantics of memset is dictated by the corresponding // LLVM intrinsics, not by the libc API. -export fn memset(dest: ?&u8, c: u8, n: usize) { +extern fn memset(dest: ?&u8, c: u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -27,7 +41,7 @@ export fn memset(dest: ?&u8, c: u8, n: usize) { // Note that memcpy does not return `dest`, like the libc API. // The semantics of memcpy is dictated by the corresponding // LLVM intrinsics, not by the libc API. -export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { +extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -35,25 +49,21 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { (??dest)[index] = (??src)[index]; } -export fn __stack_chk_fail() -> noreturn { - if (builtin.mode == builtin.Mode.ReleaseFast or builtin.os == builtin.Os.windows) { - @setGlobalLinkage(__stack_chk_fail, builtin.GlobalLinkage.Internal); - unreachable; - } +extern fn __stack_chk_fail() -> noreturn { @panic("stack smashing detected"); } const math = @import("../math/index.zig"); -export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } -export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } +extern fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } +extern fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } // TODO add intrinsics for these (and probably the double version too) // and have the math stuff use the intrinsic. same as @mod and @rem -export fn floorf(x: f32) -> f32 { math.floor(x) } -export fn ceilf(x: f32) -> f32 { math.ceil(x) } -export fn floor(x: f64) -> f64 { math.floor(x) } -export fn ceil(x: f64) -> f64 { math.ceil(x) } +extern fn floorf(x: f32) -> f32 { math.floor(x) } +extern fn ceilf(x: f32) -> f32 { math.ceil(x) } +extern fn floor(x: f64) -> f64 { math.floor(x) } +extern fn ceil(x: f64) -> f64 { math.ceil(x) } fn generic_fmod(comptime T: type, x: T, y: T) -> T { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/aulldiv.zig b/std/special/compiler_rt/aulldiv.zig index 511aa91f80..9d4faf95b9 100644 --- a/std/special/compiler_rt/aulldiv.zig +++ b/std/special/compiler_rt/aulldiv.zig @@ -1,66 +1,55 @@ -const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; -const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; - -export nakedcc fn _aulldiv() { - if (is_win32) { - @setDebugSafety(this, false); - @setGlobalLinkage(_aulldiv, linkage); - asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ push esi - \\ mov eax,dword ptr [esp+18h] - \\ or eax,eax - \\ jne L1 - \\ mov ecx,dword ptr [esp+14h] - \\ mov eax,dword ptr [esp+10h] - \\ xor edx,edx - \\ div ecx - \\ mov ebx,eax - \\ mov eax,dword ptr [esp+0Ch] - \\ div ecx - \\ mov edx,ebx - \\ jmp L2 - \\ L1: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+14h] - \\ mov edx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ L3: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3 - \\ div ebx - \\ mov esi,eax - \\ mul dword ptr [esp+18h] - \\ mov ecx,eax - \\ mov eax,dword ptr [esp+14h] - \\ mul esi - \\ add edx,ecx - \\ jb L4 - \\ cmp edx,dword ptr [esp+10h] - \\ ja L4 - \\ jb L5 - \\ cmp eax,dword ptr [esp+0Ch] - \\ jbe L5 - \\ L4: - \\ dec esi - \\ L5: - \\ xor edx,edx - \\ mov eax,esi - \\ L2: - \\ pop esi - \\ pop ebx - \\ ret 10h - ); - unreachable; - } - - @setGlobalLinkage(_aulldiv, builtin.GlobalLinkage.Internal); - unreachable; +pub nakedcc fn _aulldiv() { + @setDebugSafety(this, false); + asm volatile ( + \\.intel_syntax noprefix + \\ + \\ push ebx + \\ push esi + \\ mov eax,dword ptr [esp+18h] + \\ or eax,eax + \\ jne L1 + \\ mov ecx,dword ptr [esp+14h] + \\ mov eax,dword ptr [esp+10h] + \\ xor edx,edx + \\ div ecx + \\ mov ebx,eax + \\ mov eax,dword ptr [esp+0Ch] + \\ div ecx + \\ mov edx,ebx + \\ jmp L2 + \\ L1: + \\ mov ecx,eax + \\ mov ebx,dword ptr [esp+14h] + \\ mov edx,dword ptr [esp+10h] + \\ mov eax,dword ptr [esp+0Ch] + \\ L3: + \\ shr ecx,1 + \\ rcr ebx,1 + \\ shr edx,1 + \\ rcr eax,1 + \\ or ecx,ecx + \\ jne L3 + \\ div ebx + \\ mov esi,eax + \\ mul dword ptr [esp+18h] + \\ mov ecx,eax + \\ mov eax,dword ptr [esp+14h] + \\ mul esi + \\ add edx,ecx + \\ jb L4 + \\ cmp edx,dword ptr [esp+10h] + \\ ja L4 + \\ jb L5 + \\ cmp eax,dword ptr [esp+0Ch] + \\ jbe L5 + \\ L4: + \\ dec esi + \\ L5: + \\ xor edx,edx + \\ mov eax,esi + \\ L2: + \\ pop esi + \\ pop ebx + \\ ret 10h + ); } diff --git a/std/special/compiler_rt/aullrem.zig b/std/special/compiler_rt/aullrem.zig index e218890959..b6c54d33ae 100644 --- a/std/special/compiler_rt/aullrem.zig +++ b/std/special/compiler_rt/aullrem.zig @@ -1,67 +1,56 @@ -const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; -const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; - -export nakedcc fn _aullrem() { - if (is_win32) { - @setDebugSafety(this, false); - @setGlobalLinkage(_aullrem, linkage); - asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ mov eax,dword ptr [esp+14h] - \\ or eax,eax - \\ jne L1a - \\ mov ecx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ xor edx,edx - \\ div ecx - \\ mov eax,dword ptr [esp+8] - \\ div ecx - \\ mov eax,edx - \\ xor edx,edx - \\ jmp L2a - \\ L1a: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+10h] - \\ mov edx,dword ptr [esp+0Ch] - \\ mov eax,dword ptr [esp+8] - \\ L3a: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3a - \\ div ebx - \\ mov ecx,eax - \\ mul dword ptr [esp+14h] - \\ xchg eax,ecx - \\ mul dword ptr [esp+10h] - \\ add edx,ecx - \\ jb L4a - \\ cmp edx,dword ptr [esp+0Ch] - \\ ja L4a - \\ jb L5a - \\ cmp eax,dword ptr [esp+8] - \\ jbe L5a - \\ L4a: - \\ sub eax,dword ptr [esp+10h] - \\ sbb edx,dword ptr [esp+14h] - \\ L5a: - \\ sub eax,dword ptr [esp+8] - \\ sbb edx,dword ptr [esp+0Ch] - \\ neg edx - \\ neg eax - \\ sbb edx,0 - \\ L2a: - \\ pop ebx - \\ ret 10h - ); - unreachable; - } - - @setGlobalLinkage(_aullrem, builtin.GlobalLinkage.Internal); - unreachable; +pub nakedcc fn _aullrem() { + @setDebugSafety(this, false); + asm volatile ( + \\.intel_syntax noprefix + \\ + \\ push ebx + \\ mov eax,dword ptr [esp+14h] + \\ or eax,eax + \\ jne L1a + \\ mov ecx,dword ptr [esp+10h] + \\ mov eax,dword ptr [esp+0Ch] + \\ xor edx,edx + \\ div ecx + \\ mov eax,dword ptr [esp+8] + \\ div ecx + \\ mov eax,edx + \\ xor edx,edx + \\ jmp L2a + \\ L1a: + \\ mov ecx,eax + \\ mov ebx,dword ptr [esp+10h] + \\ mov edx,dword ptr [esp+0Ch] + \\ mov eax,dword ptr [esp+8] + \\ L3a: + \\ shr ecx,1 + \\ rcr ebx,1 + \\ shr edx,1 + \\ rcr eax,1 + \\ or ecx,ecx + \\ jne L3a + \\ div ebx + \\ mov ecx,eax + \\ mul dword ptr [esp+14h] + \\ xchg eax,ecx + \\ mul dword ptr [esp+10h] + \\ add edx,ecx + \\ jb L4a + \\ cmp edx,dword ptr [esp+0Ch] + \\ ja L4a + \\ jb L5a + \\ cmp eax,dword ptr [esp+8] + \\ jbe L5a + \\ L4a: + \\ sub eax,dword ptr [esp+10h] + \\ sbb edx,dword ptr [esp+14h] + \\ L5a: + \\ sub eax,dword ptr [esp+8] + \\ sbb edx,dword ptr [esp+0Ch] + \\ neg edx + \\ neg eax + \\ sbb edx,0 + \\ L2a: + \\ pop ebx + \\ ret 10h + ); } diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig index f1552ca61f..0834072672 100644 --- a/std/special/compiler_rt/comparetf2.zig +++ b/std/special/compiler_rt/comparetf2.zig @@ -20,11 +20,9 @@ const infRep = exponentMask; const builtin = @import("builtin"); const is_test = builtin.is_test; -const linkage = @import("index.zig").linkage; -export fn __letf2(a: f128, b: f128) -> c_int { +pub extern fn __letf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); - @setGlobalLinkage(__letf2, linkage); const aInt = @bitCast(rep_t, a); const bInt = @bitCast(rep_t, b); @@ -63,14 +61,6 @@ export fn __letf2(a: f128, b: f128) -> c_int { }; } -// Alias for libgcc compatibility -// TODO https://github.com/zig-lang/zig/issues/420 -export fn __cmptf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__cmptf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - // TODO https://github.com/zig-lang/zig/issues/305 // and then make the return types of some of these functions the enum instead of c_int const GE_LESS = c_int(-1); @@ -78,8 +68,7 @@ const GE_EQUAL = c_int(0); const GE_GREATER = c_int(1); const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED -export fn __getf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__getf2, linkage); +pub extern fn __getf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); const aInt = @bitCast(srep_t, a); @@ -108,38 +97,10 @@ export fn __getf2(a: f128, b: f128) -> c_int { }; } -export fn __unordtf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__unordtf2, linkage); +pub extern fn __unordtf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); const aAbs = @bitCast(rep_t, a) & absMask; const bAbs = @bitCast(rep_t, b) & absMask; return c_int(aAbs > infRep or bAbs > infRep); } - -// The following are alternative names for the preceding routines. -// TODO use aliases https://github.com/zig-lang/zig/issues/462 - -export fn __eqtf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__eqtf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __lttf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__lttf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __netf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__netf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __gttf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__gttf2, linkage); - @setDebugSafety(this, is_test); - return __getf2(a, b); -} diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/std/special/compiler_rt/fixunsdfdi.zig index 5f730bbc85..7e33987997 100644 --- a/std/special/compiler_rt/fixunsdfdi.zig +++ b/std/special/compiler_rt/fixunsdfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfdi(a: f64) -> u64 { +pub extern fn __fixunsdfdi(a: f64) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfdi, linkage); return fixuint(f64, u64, a); } diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/std/special/compiler_rt/fixunsdfsi.zig index 784d5fde4f..e710e1852b 100644 --- a/std/special/compiler_rt/fixunsdfsi.zig +++ b/std/special/compiler_rt/fixunsdfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfsi(a: f64) -> u32 { +pub extern fn __fixunsdfsi(a: f64) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfsi, linkage); return fixuint(f64, u32, a); } diff --git a/std/special/compiler_rt/fixunsdfti.zig b/std/special/compiler_rt/fixunsdfti.zig index 579455c2f9..79d924f0a8 100644 --- a/std/special/compiler_rt/fixunsdfti.zig +++ b/std/special/compiler_rt/fixunsdfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfti(a: f64) -> u128 { +pub extern fn __fixunsdfti(a: f64) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfti, linkage); return fixuint(f64, u128, a); } diff --git a/std/special/compiler_rt/fixunssfdi.zig b/std/special/compiler_rt/fixunssfdi.zig index eab553d8c9..f72f62d68c 100644 --- a/std/special/compiler_rt/fixunssfdi.zig +++ b/std/special/compiler_rt/fixunssfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfdi(a: f32) -> u64 { +pub extern fn __fixunssfdi(a: f32) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfdi, linkage); return fixuint(f32, u64, a); } diff --git a/std/special/compiler_rt/fixunssfsi.zig b/std/special/compiler_rt/fixunssfsi.zig index 18c0e66677..4c9a5001ab 100644 --- a/std/special/compiler_rt/fixunssfsi.zig +++ b/std/special/compiler_rt/fixunssfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfsi(a: f32) -> u32 { +pub extern fn __fixunssfsi(a: f32) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfsi, linkage); return fixuint(f32, u32, a); } diff --git a/std/special/compiler_rt/fixunssfti.zig b/std/special/compiler_rt/fixunssfti.zig index f513604247..59b94cfc51 100644 --- a/std/special/compiler_rt/fixunssfti.zig +++ b/std/special/compiler_rt/fixunssfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfti(a: f32) -> u128 { +pub extern fn __fixunssfti(a: f32) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfti, linkage); return fixuint(f32, u128, a); } diff --git a/std/special/compiler_rt/fixunstfdi.zig b/std/special/compiler_rt/fixunstfdi.zig index 85212e2176..06b117a414 100644 --- a/std/special/compiler_rt/fixunstfdi.zig +++ b/std/special/compiler_rt/fixunstfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfdi(a: f128) -> u64 { +pub extern fn __fixunstfdi(a: f128) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfdi, linkage); return fixuint(f128, u64, a); } diff --git a/std/special/compiler_rt/fixunstfsi.zig b/std/special/compiler_rt/fixunstfsi.zig index 33c85c9224..8a5efe711d 100644 --- a/std/special/compiler_rt/fixunstfsi.zig +++ b/std/special/compiler_rt/fixunstfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfsi(a: f128) -> u32 { +pub extern fn __fixunstfsi(a: f128) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfsi, linkage); return fixuint(f128, u32, a); } diff --git a/std/special/compiler_rt/fixunstfti.zig b/std/special/compiler_rt/fixunstfti.zig index 1bf7fbab4b..d8b654d3a3 100644 --- a/std/special/compiler_rt/fixunstfti.zig +++ b/std/special/compiler_rt/fixunstfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfti(a: f128) -> u128 { +pub extern fn __fixunstfti(a: f128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfti, linkage); return fixuint(f128, u128, a); } diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index bea06a0b41..717c6934f5 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -1,33 +1,74 @@ -comptime { - _ = @import("comparetf2.zig"); - _ = @import("fixunsdfdi.zig"); - _ = @import("fixunsdfsi.zig"); - _ = @import("fixunsdfti.zig"); - _ = @import("fixunssfdi.zig"); - _ = @import("fixunssfsi.zig"); - _ = @import("fixunssfti.zig"); - _ = @import("fixunstfdi.zig"); - _ = @import("fixunstfsi.zig"); - _ = @import("fixunstfti.zig"); - _ = @import("udivmoddi4.zig"); - _ = @import("udivmodti4.zig"); - _ = @import("udivti3.zig"); - _ = @import("umodti3.zig"); - _ = @import("aulldiv.zig"); - _ = @import("aullrem.zig"); -} - const builtin = @import("builtin"); const is_test = builtin.is_test; -const assert = @import("../../debug.zig").assert; +comptime { + const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; + const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; + + @exportWithLinkage("__letf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__getf2", @import("comparetf2.zig").__getf2, linkage); + + if (!is_test) { + // only create these aliases when not testing + @exportWithLinkage("__cmptf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__eqtf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__lttf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__netf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__gttf2", @import("comparetf2.zig").__getf2, linkage); + } + + @exportWithLinkage("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); + + @exportWithLinkage("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); + @exportWithLinkage("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); + @exportWithLinkage("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); + + @exportWithLinkage("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); + @exportWithLinkage("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); + @exportWithLinkage("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); + + @exportWithLinkage("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); + @exportWithLinkage("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); + @exportWithLinkage("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + + @exportWithLinkage("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); + @exportWithLinkage("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); -const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; -const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; -const win32_nocrt = win32 and !builtin.link_libc; -const win64_nocrt = win64 and !builtin.link_libc; -pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; -const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; + @exportWithLinkage("__udivti3", @import("udivti3.zig").__udivti3, linkage); + @exportWithLinkage("__umodti3", @import("umodti3.zig").__umodti3, linkage); + + @exportWithLinkage("__udivsi3", __udivsi3, linkage); + @exportWithLinkage("__udivdi3", __udivdi3, linkage); + @exportWithLinkage("__umoddi3", __umoddi3, linkage); + @exportWithLinkage("__udivmodsi4", __udivmodsi4, linkage); + + if (isArmArch()) { + @exportWithLinkage("__aeabi_uldivmod", __aeabi_uldivmod, linkage); + @exportWithLinkage("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + @exportWithLinkage("__aeabi_uidiv", __udivsi3, linkage); + } + if (builtin.os == builtin.Os.windows) { + switch (builtin.arch) { + builtin.Arch.i386 => { + if (!builtin.link_libc) { + @exportWithLinkage("_chkstk", _chkstk, strong_linkage); + @exportWithLinkage("__chkstk_ms", __chkstk_ms, linkage); + } + @exportWithLinkage("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); + @exportWithLinkage("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); + }, + builtin.Arch.x86_64 => { + if (!builtin.link_libc) { + @exportWithLinkage("__chkstk", __chkstk, strong_linkage); + @exportWithLinkage("___chkstk_ms", ___chkstk_ms, linkage); + } + }, + else => {}, + } + } +} + +const assert = @import("../../debug.zig").assert; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -41,15 +82,13 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } -export fn __udivdi3(a: u64, b: u64) -> u64 { +extern fn __udivdi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivdi3, linkage); return __udivmoddi4(a, b, null); } -export fn __umoddi3(a: u64, b: u64) -> u64 { +extern fn __umoddi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__umoddi3, linkage); var r: u64 = undefined; _ = __udivmoddi4(a, b, &r); @@ -60,17 +99,11 @@ const AeabiUlDivModResult = extern struct { quot: u64, rem: u64, }; -export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { +extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { @setDebugSafety(this, is_test); - if (comptime isArmArch()) { - @setGlobalLinkage(__aeabi_uldivmod, linkage); - var result: AeabiUlDivModResult = undefined; - result.quot = __udivmoddi4(numerator, denominator, &result.rem); - return result; - } - - @setGlobalLinkage(__aeabi_uldivmod, builtin.GlobalLinkage.Internal); - unreachable; + var result: AeabiUlDivModResult = undefined; + result.quot = __udivmoddi4(numerator, denominator, &result.rem); + return result; } fn isArmArch() -> bool { @@ -98,156 +131,124 @@ fn isArmArch() -> bool { }; } -export nakedcc fn __aeabi_uidivmod() { +nakedcc fn __aeabi_uidivmod() { @setDebugSafety(this, false); - - if (comptime isArmArch()) { - @setGlobalLinkage(__aeabi_uidivmod, linkage); - asm volatile ( - \\ push { lr } - \\ sub sp, sp, #4 - \\ mov r2, sp - \\ bl __udivmodsi4 - \\ ldr r1, [sp] - \\ add sp, sp, #4 - \\ pop { pc } - ::: "r2", "r1"); - unreachable; - } - - @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push { lr } + \\ sub sp, sp, #4 + \\ mov r2, sp + \\ bl __udivmodsi4 + \\ ldr r1, [sp] + \\ add sp, sp, #4 + \\ pop { pc } + ::: "r2", "r1"); } // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, // then decrement %esp by %eax. Preserves all registers except %esp and flags. // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx -export nakedcc fn _chkstk() align(4) { +nakedcc fn _chkstk() align(4) { @setDebugSafety(this, false); - if (win32_nocrt) { - @setGlobalLinkage(_chkstk, strong_linkage); - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%ecx + \\ push %%eax + \\ cmp $0x1000,%%eax + \\ lea 12(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ pop %%eax + \\ pop %%ecx + \\ ret + ); } -export nakedcc fn __chkstk() align(4) { +nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); - if (win64_nocrt) { - @setGlobalLinkage(__chkstk, strong_linkage); - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret + ); } // _chkstk routine // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx -export nakedcc fn __chkstk_ms() align(4) { +nakedcc fn __chkstk_ms() align(4) { @setDebugSafety(this, false); - if (win32_nocrt) { - @setGlobalLinkage(__chkstk_ms, linkage); - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%ecx + \\ push %%eax + \\ cmp $0x1000,%%eax + \\ lea 12(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ pop %%eax + \\ pop %%ecx + \\ ret + ); } -export nakedcc fn ___chkstk_ms() align(4) { +nakedcc fn ___chkstk_ms() align(4) { @setDebugSafety(this, false); - if (win64_nocrt) { - @setGlobalLinkage(___chkstk_ms, linkage); - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret + ); } -export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { +extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivmodsi4, linkage); const d = __udivsi3(a, b); *rem = u32(i32(a) -% (i32(d) * i32(b))); @@ -255,19 +256,8 @@ export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { } -// TODO make this an alias instead of an extra function call -// https://github.com/andrewrk/zig/issues/256 - -export fn __aeabi_uidiv(n: u32, d: u32) -> u32 { +extern fn __udivsi3(n: u32, d: u32) -> u32 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__aeabi_uidiv, linkage); - - return __udivsi3(n, d); -} - -export fn __udivsi3(n: u32, d: u32) -> u32 { - @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivsi3, linkage); const n_uword_bits: c_uint = u32.bit_count; // special cases @@ -463,4 +453,3 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) { const q: u32 = __udivsi3(a, b); assert(q == expected_q); } - diff --git a/std/special/compiler_rt/udivmoddi4.zig b/std/special/compiler_rt/udivmoddi4.zig index 8005538d9a..4e2117cfa5 100644 --- a/std/special/compiler_rt/udivmoddi4.zig +++ b/std/special/compiler_rt/udivmoddi4.zig @@ -1,10 +1,8 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { +pub extern fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivmoddi4, linkage); return udivmod(u64, a, b, maybe_rem); } diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig index 2ee2fdb57f..c56a958f27 100644 --- a/std/special/compiler_rt/udivmodti4.zig +++ b/std/special/compiler_rt/udivmodti4.zig @@ -1,10 +1,8 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { +pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivmodti4, linkage); return udivmod(u128, a, b, maybe_rem); } diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig index 3764449758..115c748cfb 100644 --- a/std/special/compiler_rt/udivti3.zig +++ b/std/special/compiler_rt/udivti3.zig @@ -1,9 +1,7 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivti3(a: u128, b: u128) -> u128 { +pub extern fn __udivti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivti3, linkage); return __udivmodti4(a, b, null); } diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig index 0ad9e127b3..9f680369eb 100644 --- a/std/special/compiler_rt/umodti3.zig +++ b/std/special/compiler_rt/umodti3.zig @@ -1,10 +1,8 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __umodti3(a: u128, b: u128) -> u128 { +pub extern fn __umodti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__umodti3, linkage); var r: u128 = undefined; _ = __udivmodti4(a, b, &r); return r; diff --git a/test/cases/asm.zig b/test/cases/asm.zig index 8a3020fe23..d7b88bd69e 100644 --- a/test/cases/asm.zig +++ b/test/cases/asm.zig @@ -2,23 +2,24 @@ const config = @import("builtin"); const assert = @import("std").debug.assert; comptime { + @export("derp", derp); if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { asm volatile ( - \\.globl aoeu; - \\.type aoeu, @function; - \\.set aoeu, derp; + \\.globl my_aoeu_symbol_asdf; + \\.type my_aoeu_symbol_asdf, @function; + \\.set my_aoeu_symbol_asdf, derp; ); } } test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(aoeu() == 1234); + assert(my_aoeu_symbol_asdf() == 1234); } } -extern fn aoeu() -> i32; +extern fn my_aoeu_symbol_asdf() -> i32; -export fn derp() -> i32 { +extern fn derp() -> i32 { return 1234; } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index e5e6575fab..1511c84b0c 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -12,8 +12,10 @@ test "empty function with comments" { emptyFunctionWithComments(); } -export fn disabledExternFn() { - @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal); +comptime { + @exportWithLinkage("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal) +} +extern fn disabledExternFn() { } test "call disabled extern fn" { @@ -533,7 +535,10 @@ var global_ptr = &gdt[0]; // can't really run this test but we can make sure it has no compile error // and generates code const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000]; -export fn writeToVRam() { +comptime { + @export("writeToVRam", writeToVRam); +} +extern fn writeToVRam() { vram[0] = 'X'; } @@ -557,3 +562,15 @@ fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA { var a = ptr; return a; } + +test "function and variable in weird section" { + if (builtin.os == builtin.Os.linux or builtin.os == builtin.Os.windows) { + // macos can't handle this + assert(fnInWeirdSection() == 1234); + } +} + +var varInWeirdSection: i32 section(".data2") = 1234; +fn fnInWeirdSection() section(".text2") -> i32 { + return varInWeirdSection; +} diff --git a/test/compare_output.zig b/test/compare_output.zig index ad9c91ff20..4829a39fb6 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -4,7 +4,8 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ _ = c.puts(c"Hello, world!"); \\ return 0; \\} @@ -137,7 +138,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); @@ -282,7 +284,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("expose function pointer to C land", \\const c = @cImport(@cInclude("stdlib.h")); \\ - \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { + \\comptime { + \\ @export("main", main); + \\} + \\extern fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); \\ if (*a_int < *b_int) { @@ -294,7 +299,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ } \\} \\ - \\export fn main() -> c_int { + \\extern fn main() -> c_int { \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ \\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); @@ -322,7 +327,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8dbb8171c2..8aa57c4468 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,253 +1,328 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { + cases.add("wrong return type for main", + \\pub fn main() { } + , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); + + cases.add("setting a section on an extern variable", + \\extern var foo: i32 section(".text2"); + \\extern fn entry() -> i32 { + \\ return foo; + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); + + cases.add("setting a section on a local variable", + \\extern fn entry() -> i32 { + \\ var foo: i32 section(".text2") = 1234; + \\ return foo; + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); + + cases.add("setting a section on an extern fn", + \\extern fn foo() section(".text2"); + \\extern fn entry() { + \\ foo(); + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); + + cases.add("wrong types given to exportWithLinkage", + \\extern fn entry() { } + \\comptime { + \\ @exportWithLinkage("entry", entry, u32(1234)); + \\} + , + ".tmp_source.zig:3:43: error: expected type 'GlobalLinkage', found 'u32'"); + cases.add("implicit semicolon - block statement", - \\export fn entry() { + \\extern fn entry() { \\ {} \\ var good = {}; \\ ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - block expr", - \\export fn entry() { + \\extern fn entry() { \\ _ = {}; \\ var good = {}; \\ _ = {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime statement", - \\export fn entry() { + \\extern fn entry() { \\ comptime {} \\ var good = {}; \\ comptime ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = comptime {}; \\ var good = {}; \\ _ = comptime {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - defer", - \\export fn entry() { + \\extern fn entry() { \\ defer {} \\ var good = {}; \\ defer ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); cases.add("implicit semicolon - if statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} \\ var good = {}; \\ if(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {}; \\ var good = {}; \\ _ = if(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else if(true) {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else if(true) {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) else ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} else {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test statement", - \\export fn entry() { + \\extern fn entry() { \\ if (foo()) |_| {} \\ var good = {}; \\ if (foo()) |_| ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if (foo()) |_| {}; \\ var good = {}; \\ _ = if (foo()) |_| {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while statement", - \\export fn entry() { + \\extern fn entry() { \\ while(true) {} \\ var good = {}; \\ while(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = while(true) {}; \\ var good = {}; \\ _ = while(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue statement", - \\export fn entry() { + \\extern fn entry() { \\ while(true):({}) {} \\ var good = {}; \\ while(true):({}) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = while(true):({}) {}; \\ var good = {}; \\ _ = while(true):({}) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for statement", - \\export fn entry() { + \\extern fn entry() { \\ for(foo()) {} \\ var good = {}; \\ for(foo()) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = for(foo()) {}; \\ var good = {}; \\ _ = for(foo()) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("multiple function definitions", \\fn a() {} \\fn a() {} - \\export fn entry() { a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { a(); } , ".tmp_source.zig:2:1: error: redefinition of 'a'"); cases.add("unreachable with return", \\fn a() -> noreturn {return;} - \\export fn entry() { a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { a(); } , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'"); cases.add("control reaches end of non-void function", \\fn a() -> i32 {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'"); cases.add("undefined function call", - \\export fn a() { + \\extern fn a() { \\ b(); \\} + \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("wrong number of arguments", - \\export fn a() { + \\extern fn a() { \\ b(1); \\} \\fn b(a: i32, b: i32, c: i32) { } + \\comptime {@export("a", a);} , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1"); cases.add("invalid type", \\fn a() -> bogus {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'"); cases.add("pointer to unreachable", \\fn a() -> &noreturn {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed"); cases.add("unreachable code", - \\export fn a() { + \\extern fn a() { \\ return; \\ b(); \\} \\ \\fn b() {} + \\comptime {@export("a", a);} , ".tmp_source.zig:3:5: error: unreachable code"); cases.add("bad import", \\const bogus = @import("bogus-does-not-exist.zig"); - \\export fn entry() { bogus.bogo(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { bogus.bogo(); } , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'"); cases.add("undeclared identifier", - \\export fn a() { + \\extern fn a() { \\ b + \\ c \\} + \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); @@ -255,99 +330,114 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("parameter redeclaration", \\fn f(a : i32, a : i32) { \\} - \\export fn entry() { f(1, 2); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(1, 2); } , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'"); cases.add("local variable redeclaration", - \\export fn f() { + \\extern fn f() { \\ const a : i32 = 0; \\ const a = 0; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); cases.add("local variable redeclares parameter", \\fn f(a : i32) { \\ const a = 0; \\} - \\export fn entry() { f(1); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(1); } , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'"); cases.add("variable has wrong type", - \\export fn f() -> i32 { + \\extern fn f() -> i32 { \\ const a = c"a"; \\ a \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); cases.add("if condition is bool, not int", - \\export fn f() { + \\extern fn f() { \\ if (0) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); cases.add("assign unreachable", - \\export fn f() { + \\extern fn f() { \\ const a = return; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: unreachable code"); cases.add("unreachable variable", - \\export fn f() { + \\extern fn f() { \\ const a: noreturn = {}; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed"); cases.add("unreachable parameter", \\fn f(a: noreturn) {} - \\export fn entry() { f(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(); } , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed"); cases.add("bad assignment target", - \\export fn f() { + \\extern fn f() { \\ 3 = 3; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:7: error: cannot assign to constant"); cases.add("assign to constant variable", - \\export fn f() { + \\extern fn f() { \\ const a = 3; \\ a = 4; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); cases.add("use of undeclared identifier", - \\export fn f() { + \\extern fn f() { \\ b = 3; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("const is a statement, not an expression", - \\export fn f() { + \\extern fn f() { \\ (const a = 0); \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:6: error: invalid token: 'const'"); cases.add("array access of undeclared identifier", - \\export fn f() { + \\extern fn f() { \\ i[i] = i[i]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'"); cases.add("array access of non array", - \\export fn f() { + \\extern fn f() { \\ var bad : bool = undefined; \\ bad[bad] = bad[bad]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'", ".tmp_source.zig:3:19: error: array access of non-array type 'bool'"); cases.add("array access with non integer index", - \\export fn f() { + \\extern fn f() { \\ var array = "aoeu"; \\ var bad = false; \\ array[bad] = array[bad]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'"); @@ -356,7 +446,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() { \\ x = 1; \\} - \\export fn entry() { f(); } + \\extern fn entry() { f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); @@ -365,29 +456,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const x : i32 = if (b) { 1 }; \\ const y = if (b) { i32(1) }; \\} - \\export fn entry() { f(true); } + \\extern fn entry() { f(true); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); cases.add("direct struct loop", \\const A = struct { a : A, }; - \\export fn entry() -> usize { @sizeOf(A) } + \\extern fn entry() -> usize { @sizeOf(A) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("indirect struct loop", \\const A = struct { b : B, }; \\const B = struct { c : C, }; \\const C = struct { a : A, }; - \\export fn entry() -> usize { @sizeOf(A) } + \\extern fn entry() -> usize { @sizeOf(A) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("invalid struct field", \\const A = struct { x : i32, }; - \\export fn f() { + \\extern fn f() { \\ var a : A = undefined; \\ a.foo = 1; \\ const y = a.bar; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); @@ -415,7 +510,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ const a = A { \\ .z = 1, \\ .y = 2, @@ -423,6 +518,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .z = 4, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:11:9: error: duplicate field"); cases.add("missing field in struct value expression", @@ -431,7 +527,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ // we want the error on the '{' not the 'A' because \\ // the A could be a complicated expression \\ const a = A { @@ -439,6 +535,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .y = 2, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:9:17: error: missing field: 'x'"); cases.add("invalid field in struct value expression", @@ -447,69 +544,79 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ const a = A { \\ .z = 4, \\ .y = 2, \\ .foo = 42, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); cases.add("invalid break expression", - \\export fn f() { + \\extern fn f() { \\ break; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: break expression outside loop"); cases.add("invalid continue expression", - \\export fn f() { + \\extern fn f() { \\ continue; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: continue expression outside loop"); cases.add("invalid maybe type", - \\export fn f() { + \\extern fn f() { \\ if (true) |x| { } \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'"); cases.add("cast unreachable", \\fn f() -> i32 { \\ i32(return 1) \\} - \\export fn entry() { _ = f(); } + \\extern fn entry() { _ = f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: unreachable code"); cases.add("invalid builtin fn", \\fn f() -> @bogus(foo) { \\} - \\export fn entry() { _ = f(); } + \\extern fn entry() { _ = f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'"); cases.add("top level decl dependency loop", \\const a : @typeOf(b) = 0; \\const b : @typeOf(a) = 0; - \\export fn entry() { + \\extern fn entry() { \\ const c = a + b; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: 'a' depends on itself"); cases.add("noalias on non pointer param", \\fn f(noalias x: i32) {} - \\export fn entry() { f(1234); } + \\extern fn entry() { f(1234); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter"); cases.add("struct init syntax for array", \\const foo = []u16{.x = 1024,}; - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); cases.add("type variables must be constant", \\var foo = u8; - \\export fn entry() -> foo { + \\extern fn entry() -> foo { \\ return 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant"); @@ -521,9 +628,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var Bar : i32 = undefined; \\} \\ - \\export fn entry() { + \\extern fn entry() { \\ f(1234); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:6: error: redefinition of 'Foo'", ".tmp_source.zig:1:1: note: previous definition is here", @@ -545,7 +653,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); cases.add("switch expression - duplicate enumeration prong", @@ -565,7 +674,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -587,7 +697,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -599,9 +710,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => true, \\ }; \\} - \\export fn entry() { + \\extern fn entry() { \\ f(1234); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression"); cases.add("switch expression - non exhaustive integer prongs", @@ -610,7 +722,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 0 => {}, \\ } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: switch must handle all possibilities"); @@ -623,7 +736,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 206 ... 255 => 3, \\ } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: duplicate switch value", ".tmp_source.zig:5:14: note: previous value is here"); @@ -635,14 +749,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\const y: u8 = 100; - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); cases.add("global variable initializer must be constant expression", \\extern fn foo() -> i32; \\const x = foo(); - \\export fn entry() -> i32 { x } + \\extern fn entry() -> i32 { x } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); cases.add("array concatenation with wrong type", @@ -650,7 +766,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const derp = usize(1234); \\const a = derp ++ "foo"; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); cases.add("non compile time array concatenation", @@ -658,12 +775,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ s ++ "foo" \\} \\var s: [10]u8 = undefined; - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); cases.add("@cImport with bogus include", \\const c = @cImport(@cInclude("bogus.h")); - \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: C import failed", ".h:1:10: note: 'bogus.h' file not found"); @@ -671,17 +790,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x = 3; \\const y = &x; \\fn foo() -> &const i32 { y } - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); cases.add("integer overflow error", \\const x : u8 = 300; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); cases.add("incompatible number literals", \\const x = 2 == 2.0; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); cases.add("missing function call param", @@ -707,13 +829,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const result = members[index](); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); cases.add("missing function name and param name", \\fn () {} \\fn f(i32) {} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: missing function name", ".tmp_source.zig:2:6: error: missing parameter name"); @@ -723,16 +847,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn a() -> i32 {0} \\fn b() -> i32 {1} \\fn c() -> i32 {2} - \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); cases.add("extern function pointer mismatch", \\const fns = [](fn(i32)->i32){ a, b, c }; \\pub fn a(x: i32) -> i32 {x + 0} \\pub fn b(x: i32) -> i32 {x + 1} - \\export fn c(x: i32) -> i32 {x + 2} + \\extern fn c(x: i32) -> i32 {x + 2} + \\ + \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\comptime {@export("entry", entry);} + \\comptime {@export("c", c);} , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); @@ -740,14 +868,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x : f64 = 1.0; \\const y : f32 = x; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); cases.add("colliding invalid top level functions", \\fn func() -> bogus {} \\fn func() -> bogus {} - \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(func)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:1: error: redefinition of 'func'", ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); @@ -755,7 +885,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("bogus compile var", \\const x = @import("builtin").bogus; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); @@ -766,7 +897,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\var global_var: usize = 1; \\fn get() -> usize { global_var } \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(Foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:21: error: unable to evaluate constant expression", ".tmp_source.zig:2:12: note: called from here", @@ -779,7 +911,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\}; \\const x = Foo {.field = 1} + Foo {.field = 2}; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); @@ -789,10 +922,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const int_x = u32(1) / u32(0); \\const float_x = f32(1.0) / f32(0.0); \\ - \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } - \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } - \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } - \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } + \\extern fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } + \\extern fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } + \\extern fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } + \\extern fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } + \\comptime {@export("entry1", entry1);} + \\comptime {@export("entry2", entry2);} + \\comptime {@export("entry3", entry3);} + \\comptime {@export("entry4", entry4);} , ".tmp_source.zig:1:21: error: division by zero is undefined", ".tmp_source.zig:2:25: error: division by zero is undefined", @@ -804,14 +941,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const foo = "a \\b"; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); cases.add("invalid comparison for function pointers", \\fn foo() {} \\const invalid = foo > foo; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(invalid)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); cases.add("generic function instance with non-constant expression", @@ -820,16 +959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return foo(a, b); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(test1)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); cases.add("goto jumping into block", - \\export fn f() { + \\extern fn f() { \\ { \\a_label: \\ } \\ goto a_label; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); cases.add("goto jumping past a defer", @@ -840,20 +981,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\fn derp(){} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); cases.add("assign null to non-nullable pointer", \\const a: &u8 = null; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); cases.add("indexing an array of size zero", \\const array = []u8{}; - \\export fn foo() { + \\extern fn foo() { \\ const pointer = &array[0]; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:27: error: index 0 outside array of size 0"); cases.add("compile time division by zero", @@ -862,7 +1006,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 1 / x \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: division by zero is undefined", ".tmp_source.zig:1:14: note: called from here"); @@ -870,7 +1015,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("branch on undefined value", \\const x = if (undefined) true else false; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:15: error: use of undefined value"); @@ -880,7 +1026,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return fibbonaci(x - 1) + fibbonaci(x - 2); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } , ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", ".tmp_source.zig:3:21: note: called from here"); @@ -888,7 +1035,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@embedFile with bogus file", \\const resource = @embedFile("bogus.txt"); \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(resource)) } , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); cases.add("non-const expression in struct literal outside function", @@ -898,7 +1046,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const a = Foo {.x = get_it()}; \\extern fn get_it() -> i32; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); cases.add("non-const expression function call with struct return value outside function", @@ -912,18 +1061,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\var global_side_effect = false; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:6:24: error: unable to evaluate constant expression", ".tmp_source.zig:4:17: note: called from here"); cases.add("undeclared identifier error should mark fn as impure", - \\export fn foo() { + \\extern fn foo() { \\ test_a_thing(); \\} \\fn test_a_thing() { \\ bad_fn_call(); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'"); cases.add("illegal comparison of types", @@ -938,14 +1089,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ *a == *b \\} \\ - \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } - \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } + \\extern fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } + \\extern fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } + \\comptime {@export("entry1", entry1);} + \\comptime {@export("entry2", entry2);} , ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); cases.add("non-const switch number literal", - \\export fn foo() { + \\extern fn foo() { \\ const x = switch (bar()) { \\ 1, 2 => 1, \\ 3, 4 => 2, @@ -955,22 +1108,25 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar() -> i32 { \\ 2 \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: unable to infer expression type"); cases.add("atomic orderings of cmpxchg - failure stricter than success", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn f() { + \\extern fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success"); cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn f() { + \\extern fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter"); cases.add("negation overflow in function evaluation", @@ -979,7 +1135,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ -x \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: negation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -990,7 +1147,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a + b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1002,7 +1160,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a - b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1013,7 +1172,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a * b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1024,40 +1184,35 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @truncate(i8, x) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); cases.add("%return in function with non error return type", - \\export fn f() { + \\extern fn f() { \\ %return something(); \\} \\fn something() -> %void { } + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); - cases.add("wrong return type for main", - \\pub fn main() { } - , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); - - cases.add("double ?? on main return value", - \\pub fn main() -> ??void { - \\} - , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); - cases.add("invalid pointer for var type", \\extern fn ext() -> usize; \\var bytes: [ext()]u8 = undefined; - \\export fn f() { + \\extern fn f() { \\ for (bytes) |*b, i| { \\ *b = u8(i); \\ } \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:13: error: unable to evaluate constant expression"); cases.add("export function with comptime parameter", - \\export fn foo(comptime x: i32, y: i32) -> i32{ + \\extern fn foo(comptime x: i32, y: i32) -> i32{ \\ x + y \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("extern function with comptime parameter", @@ -1065,14 +1220,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() -> i32 { \\ foo(1, 2) \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("convert fixed size array to slice with invalid size", - \\export fn f() { + \\extern fn f() { \\ var array: [5]u8 = undefined; \\ var foo = ([]const u32)(array)[0]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch"); cases.add("non-pure function returns type", @@ -1090,10 +1247,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn function_with_return_type_type() { + \\extern fn function_with_return_type_type() { \\ var list: List(i32) = undefined; \\ list.length = 10; \\} + \\comptime {@export("function_with_return_type_type", function_with_return_type_type);} , ".tmp_source.zig:3:7: error: unable to evaluate constant expression", ".tmp_source.zig:16:19: note: called from here"); @@ -1102,7 +1260,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f(m: []const u8) { \\ m.copy(u8, self[0..], m); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); cases.add("wrong number of arguments for method fn call", @@ -1113,21 +1272,24 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\ foo.method(1, 2); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); cases.add("assign through constant pointer", - \\export fn f() { + \\extern fn f() { \\ var cstr = c"Hat"; \\ cstr[0] = 'W'; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("assign through constant slice", - \\export fn f() { + \\extern fn f() { \\ var cstr: []const u8 = "Hat"; \\ cstr[0] = 'W'; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("main function with bogus args type", @@ -1138,7 +1300,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(blah: []u8) { \\ for (blah) { } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); cases.add("misspelled type with pointer only reference", @@ -1171,7 +1334,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); cases.add("method call with first arg type primitive", @@ -1185,11 +1349,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\}; \\ - \\export fn f() { + \\extern fn f() { \\ const derp = Foo.init(3); \\ \\ derp.init(); \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'"); cases.add("method call with first arg type wrong container", @@ -1213,10 +1378,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ field: i32, \\}; \\ - \\export fn foo() { + \\extern fn foo() { \\ var x = List.init(&global_allocator); \\ x.init(); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'"); cases.add("binary not on number literal", @@ -1224,16 +1390,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); cases.addCase({ const tc = cases.create("multiple files with private function error", \\const foo = @import("foo.zig"); \\ - \\export fn callPrivFunction() { + \\extern fn callPrivFunction() { \\ foo.privateFunction(); \\} + \\comptime {@export("callPrivFunction", callPrivFunction);} , ".tmp_source.zig:4:8: error: 'privateFunction' is private", "foo.zig:1:1: note: declared here"); @@ -1249,17 +1417,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const zero: i32 = 0; \\const a = zero{1}; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); cases.add("assign to constant field", \\const Foo = struct { \\ field: i32, \\}; - \\export fn derp() { + \\extern fn derp() { \\ const f = Foo {.field = 1234,}; \\ f.field = 0; \\} + \\comptime {@export("derp", derp);} , ".tmp_source.zig:6:13: error: cannot assign to constant"); cases.add("return from defer expression", @@ -1277,7 +1447,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return 0; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:11: error: cannot return from defer expression"); cases.add("attempt to access var args out of bounds", @@ -1289,7 +1460,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(i32(1234)) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", ".tmp_source.zig:6:8: note: called from here"); @@ -1307,27 +1479,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(1, 2, 3, 4) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(bar)) } , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); cases.add("assign too big number to u16", - \\export fn foo() { + \\extern fn foo() { \\ var vga_mem: u16 = 0xB8000; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); cases.add("global variable alignment non power of 2", \\const some_data: [100]u8 align(3) = undefined; - \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(some_data)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); cases.add("function alignment non power of 2", \\extern fn foo() align(3); - \\export fn entry() { foo() } + \\extern fn entry() { foo() } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); cases.add("compile log", - \\export fn foo() { + \\extern fn foo() { \\ comptime bar(12, "hi"); \\} \\fn bar(a: i32, b: []const u8) { @@ -1335,6 +1511,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @compileLog("a", a, "b", b); \\ @compileLog("end"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: found compile log statement", ".tmp_source.zig:2:17: note: called from here", @@ -1358,7 +1535,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return *x; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); cases.add("referring to a struct that is invalid", @@ -1366,19 +1544,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Type: u8, \\}; \\ - \\export fn foo() { + \\extern fn foo() { \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); \\} \\ \\fn assert(ok: bool) { \\ if (!ok) unreachable; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:10:14: error: unable to evaluate constant expression", ".tmp_source.zig:6:20: note: called from here"); cases.add("control flow uses comptime var at runtime", - \\export fn foo() { + \\extern fn foo() { \\ comptime var i = 0; \\ while (i < 5) : (i += 1) { \\ bar(); @@ -1386,53 +1565,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\ \\fn bar() { } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime", ".tmp_source.zig:3:24: note: compile-time variable assigned here"); cases.add("ignored return value", - \\export fn foo() { + \\extern fn foo() { \\ bar(); \\} \\fn bar() -> i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:8: error: expression value is ignored"); cases.add("ignored assert-err-ok return value", - \\export fn foo() { + \\extern fn foo() { \\ %%bar(); \\} \\fn bar() -> %i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored statement value", - \\export fn foo() { + \\extern fn foo() { \\ 1; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored comptime statement value", - \\export fn foo() { + \\extern fn foo() { \\ comptime {1;} \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expression value is ignored"); cases.add("ignored comptime value", - \\export fn foo() { + \\extern fn foo() { \\ comptime 1; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored defered statement value", - \\export fn foo() { + \\extern fn foo() { \\ defer {1;} \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:12: error: expression value is ignored"); cases.add("ignored defered statement value", - \\export fn foo() { + \\extern fn foo() { \\ defer bar(); \\} \\fn bar() -> %i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: expression value is ignored"); cases.add("dereference an array", @@ -1443,7 +1630,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return (*out)[0..1]; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(pass)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); cases.add("pass const ptr to mutable ptr fn", @@ -1456,46 +1644,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return true; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); - cases.addCase({ - const tc = cases.create("export collision", - \\const foo = @import("foo.zig"); - \\ - \\export fn bar() -> usize { - \\ return foo.baz; - \\} - , - "foo.zig:1:8: error: exported symbol collision: 'bar'", - ".tmp_source.zig:3:8: note: other symbol is here"); - - tc.addSourceFile("foo.zig", - \\export fn bar() {} - \\pub const baz = 1234; - ); - - tc - }); - cases.add("pass non-copyable type by value to function", \\const Point = struct { x: i32, y: i32, }; \\fn foo(p: Point) { } - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); cases.add("implicit cast from array to mutable slice", \\var global_array: [10]i32 = undefined; \\fn foo(param: []i32) {} - \\export fn entry() { + \\extern fn entry() { \\ foo(global_array); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'"); cases.add("ptrcast to non-pointer", - \\export fn entry(a: &i32) -> usize { + \\extern fn entry(a: &i32) -> usize { \\ return @ptrCast(usize, a); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); cases.add("too many error values to cast to small integer", @@ -1504,7 +1677,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(e: error) -> u2 { \\ return u2(e); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); cases.add("asm at compile time", @@ -1523,41 +1697,46 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("invalid member of builtin enum", \\const builtin = @import("builtin"); - \\export fn entry() { + \\extern fn entry() { \\ const foo = builtin.Arch.x86; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'"); cases.add("int to ptr of 0 bits", - \\export fn foo() { + \\extern fn foo() { \\ var x: usize = 0x1000; \\ var y: &void = @intToPtr(&void, x); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information"); cases.add("@fieldParentPtr - non struct", \\const Foo = i32; - \\export fn foo(a: &i32) -> &Foo { + \\extern fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'"); cases.add("@fieldParentPtr - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\export fn foo(a: &i32) -> &Foo { + \\extern fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'"); cases.add("@fieldParentPtr - field pointer is not pointer", \\const Foo = struct { \\ a: i32, \\}; - \\export fn foo(a: i32) -> &Foo { + \\extern fn foo(a: i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'"); cases.add("@fieldParentPtr - comptime field ptr not based on struct", @@ -1587,18 +1766,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@offsetOf - non struct", \\const Foo = i32; - \\export fn foo() -> usize { + \\extern fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:22: error: expected struct type, found 'i32'"); cases.add("@offsetOf - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\export fn foo() -> usize { + \\extern fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'"); cases.addExe("missing main fn in executable", @@ -1611,38 +1792,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { "error: 'main' is private", ".tmp_source.zig:1:1: note: declared here"); - cases.add("@setGlobalSection extern variable", - \\extern var foo: i32; - \\comptime { - \\ @setGlobalSection(foo, ".text2"); - \\} - , - ".tmp_source.zig:3:5: error: cannot set section of external variable 'foo'", - ".tmp_source.zig:1:8: note: declared here"); - - cases.add("@setGlobalSection extern fn", - \\extern fn foo(); - \\comptime { - \\ @setGlobalSection(foo, ".text2"); - \\} - , - ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'", - ".tmp_source.zig:1:8: note: declared here"); - cases.add("returning address of local variable - simple", - \\export fn foo() -> &i32 { + \\extern fn foo() -> &i32 { \\ var a: i32 = undefined; \\ return &a; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:13: error: function returns address of local variable"); cases.add("returning address of local variable - phi", - \\export fn foo(c: bool) -> &i32 { + \\extern fn foo(c: bool) -> &i32 { \\ var a: i32 = undefined; \\ var b: i32 = undefined; \\ return if (c) &a else &b; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:12: error: function returns address of local variable"); @@ -1671,55 +1836,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:5:9: note: previous definition is here"); cases.add("while expected bool, got nullable", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) {} \\} \\fn bar() -> ?i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); cases.add("while expected bool, got error union", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) {} \\} \\fn bar() -> %i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); cases.add("while expected nullable, got bool", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> bool { true } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); cases.add("while expected nullable, got error union", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> %i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); cases.add("while expected error union, got bool", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> bool { true } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); cases.add("while expected error union, got nullable", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> ?i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); cases.add("inline fn calls itself indirectly", - \\export fn foo() { + \\extern fn foo() { \\ bar(); \\} \\inline fn bar() { @@ -1731,29 +1902,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ quux(); \\} \\extern fn quux(); + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("save reference to inline function", - \\export fn foo() { + \\extern fn foo() { \\ quux(@ptrToInt(bar)); \\} \\inline fn bar() { } \\extern fn quux(usize); + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("signed integer division", - \\export fn foo(a: i32, b: i32) -> i32 { + \\extern fn foo(a: i32, b: i32) -> i32 { \\ a / b \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); cases.add("signed integer remainder division", - \\export fn foo(a: i32, b: i32) -> i32 { + \\extern fn foo(a: i32, b: i32) -> i32 { \\ a % b \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); @@ -1792,59 +1967,65 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); cases.add("@setDebugSafety twice for same scope", - \\export fn foo() { + \\extern fn foo() { \\ @setDebugSafety(this, false); \\ @setDebugSafety(this, false); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: debug safety set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setFloatMode twice for same scope", - \\export fn foo() { + \\extern fn foo() { \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: float mode set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("array access of type", - \\export fn foo() { + \\extern fn foo() { \\ var b: u8[40] = undefined; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: array access of non-array type 'type'"); cases.add("cannot break out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ while (true) { \\ defer { \\ break; \\ } \\ } \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot break out of defer expression"); cases.add("cannot continue out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ while (true) { \\ defer { \\ continue; \\ } \\ } \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); cases.add("cannot goto out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ defer { \\ goto label; \\ }; \\label: \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); @@ -1878,9 +2059,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const bar = baz + foo; \\const baz = 1; \\ - \\export fn entry() -> i32 { + \\extern fn entry() -> i32 { \\ return bar; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: aoeu", ".tmp_source.zig:3:19: note: referenced here", @@ -1893,9 +2075,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\var foo: Foo = undefined; \\ - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(@typeOf(foo.x)); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: struct 'Foo' contains itself"); @@ -1914,16 +2097,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: float literal out of range of any type"); cases.add("explicit cast float literal to integer when there is a fraction component", - \\export fn entry() -> i32 { + \\extern fn entry() -> i32 { \\ i32(12.34) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); cases.add("non pointer given to @ptrToInt", - \\export fn entry(x: i32) -> usize { + \\extern fn entry(x: i32) -> usize { \\ @ptrToInt(x) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:15: error: expected pointer, found 'i32'"); @@ -1942,24 +2127,27 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits"); cases.add("shifting without int type or comptime known", - \\export fn entry(x: u8) -> u8 { + \\extern fn entry(x: u8) -> u8 { \\ return 0x11 << x; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known"); cases.add("shifting RHS is log2 of LHS int bit width", - \\export fn entry(x: u8, y: u8) -> u8 { + \\extern fn entry(x: u8, y: u8) -> u8 { \\ return x << y; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'"); cases.add("globally shadowing a primitive type", \\const u16 = @intType(false, 8); - \\export fn entry() { + \\extern fn entry() { \\ const a: u16 = 300; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: declaration shadows type 'u16'"); @@ -1969,7 +2157,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ bar(&foo.b); \\} @@ -1977,6 +2165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &u32) { \\ *x += 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'"); @@ -1986,7 +2175,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ foo.b += 1; \\ bar((&foo.b)[0..1]); @@ -1995,55 +2184,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: []u32) { \\ x[0] += 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'"); cases.add("increase pointer alignment in @ptrCast", - \\export fn entry() -> u32 { + \\extern fn entry() -> u32 { \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04}; \\ const ptr = @ptrCast(&u32, &bytes[0]); \\ return *ptr; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:17: error: cast increases pointer alignment", ".tmp_source.zig:3:38: note: '&u8' has alignment 1", ".tmp_source.zig:3:27: note: '&u32' has alignment 4"); cases.add("increase pointer alignment in slice resize", - \\export fn entry() -> u32 { + \\extern fn entry() -> u32 { \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04}; \\ return ([]u32)(bytes[0..])[0]; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: cast increases pointer alignment", ".tmp_source.zig:3:19: note: '[]u8' has alignment 1", ".tmp_source.zig:3:19: note: '[]u32' has alignment 4"); cases.add("@alignCast expects pointer or slice", - \\export fn entry() { + \\extern fn entry() { \\ @alignCast(4, u32(3)) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); cases.add("passing an under-aligned function pointer", - \\export fn entry() { + \\extern fn entry() { \\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234); \\} \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { \\ if (ptr() != answer) unreachable; \\} \\fn alignedSmall() align(4) -> i32 { 1234 } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); cases.add("passing a not-aligned-enough pointer to cmpxchg", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn entry() -> bool { + \\extern fn entry() -> bool { \\ var x: i32 align(1) = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} \\ return x == 5678; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1"); @@ -2069,17 +2264,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); \\extern fn bar(d: &Derp); - \\export fn foo() { + \\extern fn foo() { \\ const x = u8(1); \\ bar(@ptrCast(&c_void, &x)); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'"); cases.add("non-const variables of things that require const variables", \\const Opaque = @OpaqueType(); \\ - \\export fn entry(opaque: &Opaque) { + \\extern fn entry(opaque: &Opaque) { \\ var m2 = &2; \\ const y: u32 = *m2; \\ @@ -2099,6 +2295,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = struct { \\ fn bar(self: &const Foo) {} \\}; + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime", ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", @@ -2113,20 +2310,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:17:4: error: unreachable code"); cases.add("wrong types given to atomic order args in cmpxchg", - \\export fn entry() { + \\extern fn entry() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {} \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); - cases.add("wrong types given to setGlobalLinkage", - \\export fn entry() { - \\ @setGlobalLinkage(entry, u32(1234)); - \\} - , - ".tmp_source.zig:2:33: error: expected type 'GlobalLinkage', found 'u32'"); - cases.add("struct with invalid field", \\const std = @import("std"); \\const Allocator = std.mem.Allocator; @@ -2145,12 +2336,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ }, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ const a = MdNode.Header { \\ .text = MdText.init(&std.debug.global_allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); @@ -2162,35 +2354,39 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:5: error: @setAlignStack outside function"); cases.add("@setAlignStack in naked function", - \\export nakedcc fn entry() { + \\nakedcc fn entry() { \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); cases.add("@setAlignStack in inline function", - \\export fn entry() { + \\extern fn entry() { \\ foo(); \\} \\inline fn foo() { \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); cases.add("@setAlignStack set twice", - \\export fn entry() { + \\extern fn entry() { \\ @setAlignStack(16); \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setAlignStack too big", - \\export fn entry() { + \\extern fn entry() { \\ @setAlignStack(511 + 1); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); @@ -2221,7 +2417,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ LinkLibC, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ const tests = []TestCase { \\ Free("001"), \\ Free("002"), @@ -2236,13 +2432,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\ } \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); cases.add("field access of opaque type", \\const MyType = @OpaqueType(); \\ - \\export fn entry() -> bool { + \\extern fn entry() -> bool { \\ var x: i32 = 1; \\ return bar(@ptrCast(&MyType, &x)); \\} @@ -2250,6 +2447,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &MyType) -> bool { \\ return x.blah; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); @@ -2353,10 +2551,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); cases.add("calling var args extern function, passing array instead of pointer", - \\export fn entry() { + \\extern fn entry() { \\ foo("hello"); \\} \\pub extern fn foo(format: &const u8, ...); + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); @@ -2371,9 +2570,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() { + \\extern fn entry() { \\ var allocator: ContextAllocator = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:25: error: aoeu", ".tmp_source.zig:1:36: note: called from here", @@ -2388,9 +2588,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Five, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = Small.One; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'"); @@ -2401,9 +2602,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Three, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = Small.One; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: expected integer, found 'f32'"); @@ -2415,9 +2617,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x: u2 = Small.Two; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'"); @@ -2429,9 +2632,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = u3(Small.Two); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'"); @@ -2443,10 +2647,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var y = u3(3); \\ var x = Small(y); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'"); @@ -2458,9 +2663,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var y = Small.Two; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'"); @@ -2468,9 +2674,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = struct { \\ A: i32 = 20, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: MultipleChoice = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: enums, not structs, support field assignment"); @@ -2478,26 +2685,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = union { \\ A: i32 = 20, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: MultipleChoice = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: non-enum union field assignment", ".tmp_source.zig:1:24: note: consider 'union(enum)' here"); cases.add("enum with 0 fields", \\const Foo = enum {}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: enums must have 1 or more fields"); cases.add("union with 0 fields", \\const Foo = union {}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: unions must have 1 or more fields"); @@ -2509,9 +2719,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = MultipleChoice.C; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2526,9 +2737,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A: i32, \\ B: f64, \\}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Payload); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:17: error: enum field missing: 'C'", ".tmp_source.zig:4:5: note: declared here"); @@ -2537,9 +2749,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:24: error: union 'Foo' has no tag", ".tmp_source.zig:1:13: note: consider 'union(enum)' here"); @@ -2548,9 +2761,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(enum(f32)) { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'"); @@ -2558,9 +2772,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(u32) { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'"); @@ -2572,9 +2787,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = MultipleChoice { .C = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2591,9 +2807,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ C: bool, \\ D: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload {.A = 1234}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:5: error: enum field not found: 'D'", ".tmp_source.zig:1:16: note: enum declared here"); @@ -2604,9 +2821,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var b = Letter.B; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types", ".tmp_source.zig:1:16: note: consider 'union(enum)' here"); @@ -2615,9 +2833,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = struct { \\ A, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Letter { .A = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: struct field missing type"); @@ -2625,9 +2844,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = extern union { \\ A, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Letter { .A = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: union field missing type"); @@ -2642,9 +2862,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); @@ -2659,9 +2880,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); @@ -2671,7 +2893,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const a = Payload { .A = { 1234 } }; \\ foo(a); \\} @@ -2681,6 +2903,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => unreachable, \\ } \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:13: error: switch on union which has no attached enum", ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); @@ -2690,9 +2913,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A = 10, \\ B = 11, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = Foo(0); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", ".tmp_source.zig:1:13: note: 'Foo' declared here"); @@ -2704,9 +2928,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: Value = Letter.A; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", ".tmp_source.zig:3:5: note: field 'A' declared here"); @@ -2718,13 +2943,36 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ foo(Letter.A); \\} \\fn foo(l: Letter) { \\ var x: Value = l; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); + + cases.addCase({ + const tc = cases.create("export collision", + \\const foo = @import("foo.zig"); + \\ + \\comptime {@export("bar", bar);} + \\extern fn bar() -> usize { + \\ return foo.baz; + \\} + , + "foo.zig:2:11: error: exported symbol collision: 'bar'", + ".tmp_source.zig:3:11: note: other symbol is here"); + + tc.addSourceFile("foo.zig", + \\extern fn bar() {} + \\comptime {@export("bar", bar);} + \\pub const baz = 1234; + ); + + tc + }); + } diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index c1faa015c6..a3058e58ed 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -2,6 +2,9 @@ pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } fn bar() -> %void {} -export fn foo() { +comptime { + @export("foo", foo); +} +extern fn foo() { %%bar(); } diff --git a/test/translate_c.zig b/test/translate_c.zig index d50c7b9691..01f6622a71 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -26,7 +26,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a < 0 ? -a : a; \\} , - \\export fn abs(a: c_int) -> c_int { + \\pub fn abs(a: c_int) -> c_int { \\ return if (a < 0) -a else a; \\} ); @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn foo1(_arg_a: c_uint) -> c_uint { + \\pub fn foo1(_arg_a: c_uint) -> c_uint { \\ var a = _arg_a; \\ a +%= 1; \\ return a; \\} - \\export fn foo2(_arg_a: c_int) -> c_int { + \\pub fn foo2(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ a += 1; \\ return a; @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\export fn log2(_arg_a: c_uint) -> c_int { + \\pub fn log2(_arg_a: c_uint) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if (a < b) return b; \\ if (a < b) return b else return a; \\} @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if (a == b) return a; \\ if (a != b) return b; \\ return a; @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = a % b; \\} , - \\export fn s(a: c_int, b: c_int) -> c_int { + \\pub fn s(a: c_int, b: c_int) -> c_int { \\ var c: c_int; \\ c = (a + b); \\ c = (a - b); @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = @divTrunc(a, b); \\ c = @rem(a, b); \\} - \\export fn u(a: c_uint, b: c_uint) -> c_uint { + \\pub fn u(a: c_uint, b: c_uint) -> c_uint { \\ var c: c_uint; \\ c = (a +% b); \\ c = (a -% b); @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (a & b) ^ (a | b); \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ return (a & b) ^ (a | b); \\} ); @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if ((a < b) or (a == b)) return b; \\ if ((a >= b) and (a == b)) return a; \\ return a; @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a = tmp; \\} , - \\export fn max(_arg_a: c_int) -> c_int { + \\pub fn max(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ var tmp: c_int; \\ tmp = a; @@ -472,7 +472,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = b = a; \\} , - \\export fn max(a: c_int) { + \\pub fn max(a: c_int) { \\ var b: c_int; \\ var c: c_int; \\ c = { @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\export fn log2(_arg_a: u32) -> c_int { + \\pub fn log2(_arg_a: u32) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\void foo(void) { bar(); } , \\pub fn bar() {} - \\export fn foo() { + \\pub fn foo() { \\ bar(); \\} ); @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub const struct_Foo = extern struct { \\ field: c_int, \\}; - \\export fn read_field(foo: ?&struct_Foo) -> c_int { + \\pub fn read_field(foo: ?&struct_Foo) -> c_int { \\ return (??foo).field; \\} ); @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ ;;;;; \\} , - \\export fn foo() {} + \\pub fn foo() {} ); cases.add("undefined array global", @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} , \\pub var array: [100]c_int = undefined; - \\export fn foo(index: c_int) -> c_int { + \\pub fn foo(index: c_int) -> c_int { \\ return array[index]; \\} ); @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (int)a; \\} , - \\export fn float_to_int(a: f32) -> c_int { + \\pub fn float_to_int(a: f32) -> c_int { \\ return c_int(a); \\} ); @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return x; \\} , - \\export fn foo(x: ?&c_ushort) -> ?&c_void { + \\pub fn foo(x: ?&c_ushort) -> ?&c_void { \\ return @ptrCast(?&c_void, x); \\} ); @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return sizeof(int); \\} , - \\export fn size_of() -> usize { + \\pub fn size_of() -> usize { \\ return @sizeOf(c_int); \\} ); @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 0; \\} , - \\export fn foo() -> ?&c_int { + \\pub fn foo() -> ?&c_int { \\ return null; \\} ); @@ -612,7 +612,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 1, 2; \\} , - \\export fn foo() -> c_int { + \\pub fn foo() -> c_int { \\ return { \\ _ = 1; \\ 2 @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (1 << 2) >> 1; \\} , - \\export fn foo() -> c_int { + \\pub fn foo() -> c_int { \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); \\} ); @@ -643,7 +643,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_int = 0; \\ a += { \\ const _ref = &a; @@ -701,7 +701,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_uint = c_uint(0); \\ a +%= { \\ const _ref = &a; @@ -771,7 +771,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = u--; \\} , - \\export fn foo() { + \\pub fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -819,7 +819,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = --u; \\} , - \\export fn foo() { + \\pub fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ while (b != 0); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_int = 2; \\ while (true) { \\ a -= 1; @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ baz(); \\} , - \\export fn foo() {} - \\export fn baz() {} - \\export fn bar() { + \\pub fn foo() {} + \\pub fn baz() {} + \\pub fn bar() { \\ var f: ?extern fn() = foo; \\ (??f)(); \\ (??f)(); @@ -901,7 +901,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ *x = 1; \\} , - \\export fn foo(x: ?&c_int) { + \\pub fn foo(x: ?&c_int) { \\ (*??x) = 1; \\} ); -- cgit v1.2.3 From 9d9201c3b48873e432dc6824d42b5ca96b236daa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 02:39:43 -0500 Subject: bring back code that uses export and fix tests partial revert of 1fdebc1dc4881a00766f7c2b4b2d8ee6ad6e79b6 --- doc/langref.html.in | 6 + example/hello_world/hello_libc.zig | 8 +- example/mix_o_files/base64.zig | 5 +- example/shared_library/mathtest.zig | 5 +- src/all_types.hpp | 1 - src/ast_render.cpp | 7 +- src/codegen.cpp | 3 +- src/ir.cpp | 14 +- src/parser.cpp | 30 +- src/translate_c.cpp | 5 +- std/special/bootstrap.zig | 7 +- std/special/builtin.zig | 35 +- std/special/compiler_rt/index.zig | 68 +-- test/cases/asm.zig | 13 +- test/cases/misc.zig | 20 +- test/compare_output.zig | 16 +- test/compile_errors.zig | 829 +++++++++++++----------------------- test/standalone/issue_339/test.zig | 5 +- test/translate_c.zig | 64 +-- 19 files changed, 443 insertions(+), 698 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index beb113682a..e17e1ecd8f 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -136,6 +136,7 @@
  • @divFloor
  • @divTrunc
  • @embedFile
  • +
  • @export
  • @tagName
  • @EnumTagType
  • @errorName
  • @@ -4368,6 +4369,11 @@ test.zig:6:2: error: found compile log statement +

    @export

    +
    @export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) -> []const u8
    +

    + Creates a symbol in the output object file. +

    @tagName

    @tagName(value: var) -> []const u8

    diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index 16d0f303cc..ea8aec1e4f 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -5,13 +5,9 @@ const c = @cImport({ @cInclude("string.h"); }); -comptime { - @export("main", main); -} - -extern fn main(argc: c_int, argv: &&u8) -> c_int { - const msg = c"Hello, world!\n"; +const msg = c"Hello, world!\n"; +export fn main(argc: c_int, argv: &&u8) -> c_int { if (c.printf(msg) != c_int(c.strlen(msg))) return -1; diff --git a/example/mix_o_files/base64.zig b/example/mix_o_files/base64.zig index a8358e9685..49c9bc6012 100644 --- a/example/mix_o_files/base64.zig +++ b/example/mix_o_files/base64.zig @@ -1,9 +1,6 @@ const base64 = @import("std").base64; -comptime { - @export("decode_base_64", decode_base_64); -} -extern fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { +export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { const src = source_ptr[0..source_len]; const dest = dest_ptr[0..dest_len]; const base64_decoder = base64.standard_decoder_unsafe; diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig index f6d0a61c90..a11642554f 100644 --- a/example/shared_library/mathtest.zig +++ b/example/shared_library/mathtest.zig @@ -1,6 +1,3 @@ -comptime { - @export("add", add); -} -extern fn add(a: i32, b: i32) -> i32 { +export fn add(a: i32, b: i32) -> i32 { a + b } diff --git a/src/all_types.hpp b/src/all_types.hpp index 1ec3c809a2..28477c8107 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1285,7 +1285,6 @@ enum BuiltinFnId { BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, BuiltinFnIdExport, - BuiltinFnIdExportWithLinkage, }; struct BuiltinFnEntry { diff --git a/src/ast_render.cpp b/src/ast_render.cpp index fc01c79ca6..c22c16d90a 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -111,6 +111,10 @@ static const char *extern_string(bool is_extern) { return is_extern ? "extern " : ""; } +static const char *export_string(bool is_export) { + return is_export ? "export " : ""; +} + //static const char *calling_convention_string(CallingConvention cc) { // switch (cc) { // case CallingConventionUnspecified: return ""; @@ -410,8 +414,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { { const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *extern_str = extern_string(node->data.fn_proto.is_extern); + const char *export_str = export_string(node->data.fn_proto.is_export); const char *inline_str = inline_string(node->data.fn_proto.is_inline); - fprintf(ar->f, "%s%s%sfn", pub_str, inline_str, extern_str); + fprintf(ar->f, "%s%s%s%sfn", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { fprintf(ar->f, " "); print_symbol(ar, node->data.fn_proto.name); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5be26eb445..7fe4f95f85 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5016,8 +5016,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); - create_builtin_fn(g, BuiltinFnIdExport, "export", 2); - create_builtin_fn(g, BuiltinFnIdExportWithLinkage, "exportWithLinkage", 3); + create_builtin_fn(g, BuiltinFnIdExport, "export", 3); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 4afc1a2c60..7bd045bd92 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4739,7 +4739,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdExport: - case BuiltinFnIdExportWithLinkage: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); @@ -4751,15 +4750,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *arg2_value; - if (builtin_fn->id == BuiltinFnIdExportWithLinkage) { - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_instruction) - return arg2_value; - } else { - arg2_value = nullptr; - } + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); } diff --git a/src/parser.cpp b/src/parser.cpp index cc337471ba..579fe85f3b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -740,9 +740,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo return node; } else if (token->id == TokenIdAtSign) { *token_index += 1; - Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); + Token *name_tok = &pc->tokens->at(*token_index); + Buf *name_buf; + if (name_tok->id == TokenIdKeywordExport) { + name_buf = buf_create_from_str("export"); + *token_index += 1; + } else if (name_tok->id == TokenIdSymbol) { + name_buf = token_buf(name_tok); + *token_index += 1; + } else { + ast_expect_token(pc, name_tok, TokenIdSymbol); + zig_unreachable(); + } + AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); - name_node->data.symbol_expr.symbol = token_buf(name_tok); + name_node->data.symbol_expr.symbol = name_buf; AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); node->data.fn_call_expr.fn_ref_expr = name_node; @@ -2254,12 +2266,22 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); cc = CallingConventionStdcall; } else if (first_token->id == TokenIdKeywordExtern) { + is_extern = true; *token_index += 1; - fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); + Token *next_token = &pc->tokens->at(*token_index); + if (next_token->id == TokenIdKeywordFn) { + fn_token = next_token; + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, next_token, TokenIdKeywordFn); + zig_unreachable(); + } else { + *token_index -= 1; + return nullptr; + } cc = CallingConventionC; } else if (first_token->id == TokenIdKeywordFn) { fn_token = first_token; - is_extern = true; *token_index += 1; cc = CallingConventionUnspecified; } else if (mandatory) { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 77afc38a51..eba594e085 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -73,6 +73,7 @@ struct Context { ImportTableEntry *import; ZigList *errors; VisibMod visib_mod; + bool want_export; AstNode *root; HashMap decl_table; HashMap macro_table; @@ -3250,8 +3251,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { StorageClass sc = fn_decl->getStorageClass(); if (sc == SC_None) { - // TODO add export decl proto_node->data.fn_proto.visib_mod = c->visib_mod; + proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false; } else if (sc == SC_Extern || sc == SC_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_PrivateExtern) { @@ -4274,8 +4275,10 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { c->visib_mod = VisibModPub; + c->want_export = false; } else { c->visib_mod = VisibModPub; + c->want_export = true; } c->decl_table.init(8); c->macro_table.init(8); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index ee63467305..177e245400 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -8,12 +8,13 @@ const builtin = @import("builtin"); var argc_ptr: &usize = undefined; comptime { + const strong_linkage = builtin.GlobalLinkage.Strong; if (builtin.link_libc) { - @export("main", main); + @export("main", main, strong_linkage); } else if (builtin.os == builtin.Os.windows) { - @export("WinMainCRTStartup", WinMainCRTStartup); + @export("WinMainCRTStartup", WinMainCRTStartup, strong_linkage); } else { - @export("_start", _start); + @export("_start", _start, strong_linkage); } } diff --git a/std/special/builtin.zig b/std/special/builtin.zig index 9ace9b46ca..a2455a9690 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -13,24 +13,10 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } -comptime { - @export("memset", memset); - @export("memcpy", memcpy); - @export("fmodf", fmodf); - @export("fmod", fmod); - @export("floorf", floorf); - @export("ceilf", ceilf); - @export("floor", floor); - @export("ceil", ceil); - if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { - @export("__stack_chk_fail", __stack_chk_fail); - } -} - // Note that memset does not return `dest`, like the libc API. // The semantics of memset is dictated by the corresponding // LLVM intrinsics, not by the libc API. -extern fn memset(dest: ?&u8, c: u8, n: usize) { +export fn memset(dest: ?&u8, c: u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -41,7 +27,7 @@ extern fn memset(dest: ?&u8, c: u8, n: usize) { // Note that memcpy does not return `dest`, like the libc API. // The semantics of memcpy is dictated by the corresponding // LLVM intrinsics, not by the libc API. -extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { +export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -49,21 +35,26 @@ extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { (??dest)[index] = (??src)[index]; } +comptime { + if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { + @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong); + } +} extern fn __stack_chk_fail() -> noreturn { @panic("stack smashing detected"); } const math = @import("../math/index.zig"); -extern fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } -extern fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } +export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } +export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } // TODO add intrinsics for these (and probably the double version too) // and have the math stuff use the intrinsic. same as @mod and @rem -extern fn floorf(x: f32) -> f32 { math.floor(x) } -extern fn ceilf(x: f32) -> f32 { math.ceil(x) } -extern fn floor(x: f64) -> f64 { math.floor(x) } -extern fn ceil(x: f64) -> f64 { math.ceil(x) } +export fn floorf(x: f32) -> f32 { math.floor(x) } +export fn ceilf(x: f32) -> f32 { math.ceil(x) } +export fn floor(x: f64) -> f64 { math.floor(x) } +export fn ceil(x: f64) -> f64 { math.ceil(x) } fn generic_fmod(comptime T: type, x: T, y: T) -> T { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 717c6934f5..fab7b7c878 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -5,62 +5,62 @@ comptime { const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; - @exportWithLinkage("__letf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__getf2", @import("comparetf2.zig").__getf2, linkage); + @export("__letf2", @import("comparetf2.zig").__letf2, linkage); + @export("__getf2", @import("comparetf2.zig").__getf2, linkage); if (!is_test) { // only create these aliases when not testing - @exportWithLinkage("__cmptf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__eqtf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__lttf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__netf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__gttf2", @import("comparetf2.zig").__getf2, linkage); + @export("__cmptf2", @import("comparetf2.zig").__letf2, linkage); + @export("__eqtf2", @import("comparetf2.zig").__letf2, linkage); + @export("__lttf2", @import("comparetf2.zig").__letf2, linkage); + @export("__netf2", @import("comparetf2.zig").__letf2, linkage); + @export("__gttf2", @import("comparetf2.zig").__getf2, linkage); } - @exportWithLinkage("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); + @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); - @exportWithLinkage("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); - @exportWithLinkage("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); - @exportWithLinkage("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); + @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); + @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); + @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); - @exportWithLinkage("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); - @exportWithLinkage("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); - @exportWithLinkage("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); + @export("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); + @export("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); + @export("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); - @exportWithLinkage("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); - @exportWithLinkage("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); - @exportWithLinkage("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + @export("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); + @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); + @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); - @exportWithLinkage("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); - @exportWithLinkage("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); + @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); + @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); - @exportWithLinkage("__udivti3", @import("udivti3.zig").__udivti3, linkage); - @exportWithLinkage("__umodti3", @import("umodti3.zig").__umodti3, linkage); + @export("__udivti3", @import("udivti3.zig").__udivti3, linkage); + @export("__umodti3", @import("umodti3.zig").__umodti3, linkage); - @exportWithLinkage("__udivsi3", __udivsi3, linkage); - @exportWithLinkage("__udivdi3", __udivdi3, linkage); - @exportWithLinkage("__umoddi3", __umoddi3, linkage); - @exportWithLinkage("__udivmodsi4", __udivmodsi4, linkage); + @export("__udivsi3", __udivsi3, linkage); + @export("__udivdi3", __udivdi3, linkage); + @export("__umoddi3", __umoddi3, linkage); + @export("__udivmodsi4", __udivmodsi4, linkage); if (isArmArch()) { - @exportWithLinkage("__aeabi_uldivmod", __aeabi_uldivmod, linkage); - @exportWithLinkage("__aeabi_uidivmod", __aeabi_uidivmod, linkage); - @exportWithLinkage("__aeabi_uidiv", __udivsi3, linkage); + @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); + @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + @export("__aeabi_uidiv", __udivsi3, linkage); } if (builtin.os == builtin.Os.windows) { switch (builtin.arch) { builtin.Arch.i386 => { if (!builtin.link_libc) { - @exportWithLinkage("_chkstk", _chkstk, strong_linkage); - @exportWithLinkage("__chkstk_ms", __chkstk_ms, linkage); + @export("_chkstk", _chkstk, strong_linkage); + @export("__chkstk_ms", __chkstk_ms, linkage); } - @exportWithLinkage("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); - @exportWithLinkage("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); + @export("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); + @export("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); }, builtin.Arch.x86_64 => { if (!builtin.link_libc) { - @exportWithLinkage("__chkstk", __chkstk, strong_linkage); - @exportWithLinkage("___chkstk_ms", ___chkstk_ms, linkage); + @export("__chkstk", __chkstk, strong_linkage); + @export("___chkstk_ms", ___chkstk_ms, linkage); } }, else => {}, diff --git a/test/cases/asm.zig b/test/cases/asm.zig index d7b88bd69e..8a3020fe23 100644 --- a/test/cases/asm.zig +++ b/test/cases/asm.zig @@ -2,24 +2,23 @@ const config = @import("builtin"); const assert = @import("std").debug.assert; comptime { - @export("derp", derp); if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { asm volatile ( - \\.globl my_aoeu_symbol_asdf; - \\.type my_aoeu_symbol_asdf, @function; - \\.set my_aoeu_symbol_asdf, derp; + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; ); } } test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(my_aoeu_symbol_asdf() == 1234); + assert(aoeu() == 1234); } } -extern fn my_aoeu_symbol_asdf() -> i32; +extern fn aoeu() -> i32; -extern fn derp() -> i32 { +export fn derp() -> i32 { return 1234; } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 1511c84b0c..daa7c3eb98 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -13,8 +13,9 @@ test "empty function with comments" { } comptime { - @exportWithLinkage("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal) + @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); } + extern fn disabledExternFn() { } @@ -535,10 +536,7 @@ var global_ptr = &gdt[0]; // can't really run this test but we can make sure it has no compile error // and generates code const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000]; -comptime { - @export("writeToVRam", writeToVRam); -} -extern fn writeToVRam() { +export fn writeToVRam() { vram[0] = 'X'; } @@ -562,15 +560,3 @@ fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA { var a = ptr; return a; } - -test "function and variable in weird section" { - if (builtin.os == builtin.Os.linux or builtin.os == builtin.Os.windows) { - // macos can't handle this - assert(fnInWeirdSection() == 1234); - } -} - -var varInWeirdSection: i32 section(".data2") = 1234; -fn fnInWeirdSection() section(".text2") -> i32 { - return varInWeirdSection; -} diff --git a/test/compare_output.zig b/test/compare_output.zig index 4829a39fb6..ad9c91ff20 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -4,8 +4,7 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ _ = c.puts(c"Hello, world!"); \\ return 0; \\} @@ -138,8 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); @@ -284,10 +282,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("expose function pointer to C land", \\const c = @cImport(@cInclude("stdlib.h")); \\ - \\comptime { - \\ @export("main", main); - \\} - \\extern fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { + \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); \\ if (*a_int < *b_int) { @@ -299,7 +294,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ } \\} \\ - \\extern fn main() -> c_int { + \\export fn main() -> c_int { \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ \\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); @@ -327,8 +322,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8aa57c4468..22520802fb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,328 +1,253 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { - cases.add("wrong return type for main", - \\pub fn main() { } - , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); - - cases.add("double ?? on main return value", - \\pub fn main() -> ??void { - \\} - , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); - - cases.add("setting a section on an extern variable", - \\extern var foo: i32 section(".text2"); - \\extern fn entry() -> i32 { - \\ return foo; - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); - - cases.add("setting a section on a local variable", - \\extern fn entry() -> i32 { - \\ var foo: i32 section(".text2") = 1234; - \\ return foo; - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); - - cases.add("setting a section on an extern fn", - \\extern fn foo() section(".text2"); - \\extern fn entry() { - \\ foo(); - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); - - cases.add("wrong types given to exportWithLinkage", - \\extern fn entry() { } - \\comptime { - \\ @exportWithLinkage("entry", entry, u32(1234)); - \\} - , - ".tmp_source.zig:3:43: error: expected type 'GlobalLinkage', found 'u32'"); - cases.add("implicit semicolon - block statement", - \\extern fn entry() { + \\export fn entry() { \\ {} \\ var good = {}; \\ ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - block expr", - \\extern fn entry() { + \\export fn entry() { \\ _ = {}; \\ var good = {}; \\ _ = {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime statement", - \\extern fn entry() { + \\export fn entry() { \\ comptime {} \\ var good = {}; \\ comptime ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = comptime {}; \\ var good = {}; \\ _ = comptime {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - defer", - \\extern fn entry() { + \\export fn entry() { \\ defer {} \\ var good = {}; \\ defer ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); cases.add("implicit semicolon - if statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} \\ var good = {}; \\ if(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {}; \\ var good = {}; \\ _ = if(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else if(true) {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else if(true) {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) else ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} else {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test statement", - \\extern fn entry() { + \\export fn entry() { \\ if (foo()) |_| {} \\ var good = {}; \\ if (foo()) |_| ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if (foo()) |_| {}; \\ var good = {}; \\ _ = if (foo()) |_| {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while statement", - \\extern fn entry() { + \\export fn entry() { \\ while(true) {} \\ var good = {}; \\ while(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = while(true) {}; \\ var good = {}; \\ _ = while(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue statement", - \\extern fn entry() { + \\export fn entry() { \\ while(true):({}) {} \\ var good = {}; \\ while(true):({}) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = while(true):({}) {}; \\ var good = {}; \\ _ = while(true):({}) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for statement", - \\extern fn entry() { + \\export fn entry() { \\ for(foo()) {} \\ var good = {}; \\ for(foo()) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = for(foo()) {}; \\ var good = {}; \\ _ = for(foo()) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("multiple function definitions", \\fn a() {} \\fn a() {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { a(); } + \\export fn entry() { a(); } , ".tmp_source.zig:2:1: error: redefinition of 'a'"); cases.add("unreachable with return", \\fn a() -> noreturn {return;} - \\comptime {@export("entry", entry);} - \\extern fn entry() { a(); } + \\export fn entry() { a(); } , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'"); cases.add("control reaches end of non-void function", \\fn a() -> i32 {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'"); cases.add("undefined function call", - \\extern fn a() { + \\export fn a() { \\ b(); \\} - \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("wrong number of arguments", - \\extern fn a() { + \\export fn a() { \\ b(1); \\} \\fn b(a: i32, b: i32, c: i32) { } - \\comptime {@export("a", a);} , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1"); cases.add("invalid type", \\fn a() -> bogus {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'"); cases.add("pointer to unreachable", \\fn a() -> &noreturn {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed"); cases.add("unreachable code", - \\extern fn a() { + \\export fn a() { \\ return; \\ b(); \\} \\ \\fn b() {} - \\comptime {@export("a", a);} , ".tmp_source.zig:3:5: error: unreachable code"); cases.add("bad import", \\const bogus = @import("bogus-does-not-exist.zig"); - \\comptime {@export("entry", entry);} - \\extern fn entry() { bogus.bogo(); } + \\export fn entry() { bogus.bogo(); } , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'"); cases.add("undeclared identifier", - \\extern fn a() { + \\export fn a() { \\ b + \\ c \\} - \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); @@ -330,114 +255,99 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("parameter redeclaration", \\fn f(a : i32, a : i32) { \\} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(1, 2); } + \\export fn entry() { f(1, 2); } , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'"); cases.add("local variable redeclaration", - \\extern fn f() { + \\export fn f() { \\ const a : i32 = 0; \\ const a = 0; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); cases.add("local variable redeclares parameter", \\fn f(a : i32) { \\ const a = 0; \\} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(1); } + \\export fn entry() { f(1); } , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'"); cases.add("variable has wrong type", - \\extern fn f() -> i32 { + \\export fn f() -> i32 { \\ const a = c"a"; \\ a \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); cases.add("if condition is bool, not int", - \\extern fn f() { + \\export fn f() { \\ if (0) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); cases.add("assign unreachable", - \\extern fn f() { + \\export fn f() { \\ const a = return; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: unreachable code"); cases.add("unreachable variable", - \\extern fn f() { + \\export fn f() { \\ const a: noreturn = {}; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed"); cases.add("unreachable parameter", \\fn f(a: noreturn) {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(); } + \\export fn entry() { f(); } , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed"); cases.add("bad assignment target", - \\extern fn f() { + \\export fn f() { \\ 3 = 3; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:7: error: cannot assign to constant"); cases.add("assign to constant variable", - \\extern fn f() { + \\export fn f() { \\ const a = 3; \\ a = 4; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); cases.add("use of undeclared identifier", - \\extern fn f() { + \\export fn f() { \\ b = 3; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("const is a statement, not an expression", - \\extern fn f() { + \\export fn f() { \\ (const a = 0); \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:6: error: invalid token: 'const'"); cases.add("array access of undeclared identifier", - \\extern fn f() { + \\export fn f() { \\ i[i] = i[i]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'"); cases.add("array access of non array", - \\extern fn f() { + \\export fn f() { \\ var bad : bool = undefined; \\ bad[bad] = bad[bad]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'", ".tmp_source.zig:3:19: error: array access of non-array type 'bool'"); cases.add("array access with non integer index", - \\extern fn f() { + \\export fn f() { \\ var array = "aoeu"; \\ var bad = false; \\ array[bad] = array[bad]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'"); @@ -446,8 +356,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() { \\ x = 1; \\} - \\extern fn entry() { f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(); } , ".tmp_source.zig:3:7: error: cannot assign to constant"); @@ -456,33 +365,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const x : i32 = if (b) { 1 }; \\ const y = if (b) { i32(1) }; \\} - \\extern fn entry() { f(true); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(true); } , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); cases.add("direct struct loop", \\const A = struct { a : A, }; - \\extern fn entry() -> usize { @sizeOf(A) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(A) } , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("indirect struct loop", \\const A = struct { b : B, }; \\const B = struct { c : C, }; \\const C = struct { a : A, }; - \\extern fn entry() -> usize { @sizeOf(A) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(A) } , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("invalid struct field", \\const A = struct { x : i32, }; - \\extern fn f() { + \\export fn f() { \\ var a : A = undefined; \\ a.foo = 1; \\ const y = a.bar; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); @@ -510,7 +415,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ const a = A { \\ .z = 1, \\ .y = 2, @@ -518,7 +423,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .z = 4, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:11:9: error: duplicate field"); cases.add("missing field in struct value expression", @@ -527,7 +431,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ // we want the error on the '{' not the 'A' because \\ // the A could be a complicated expression \\ const a = A { @@ -535,7 +439,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .y = 2, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:9:17: error: missing field: 'x'"); cases.add("invalid field in struct value expression", @@ -544,79 +447,69 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ const a = A { \\ .z = 4, \\ .y = 2, \\ .foo = 42, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); cases.add("invalid break expression", - \\extern fn f() { + \\export fn f() { \\ break; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: break expression outside loop"); cases.add("invalid continue expression", - \\extern fn f() { + \\export fn f() { \\ continue; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: continue expression outside loop"); cases.add("invalid maybe type", - \\extern fn f() { + \\export fn f() { \\ if (true) |x| { } \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'"); cases.add("cast unreachable", \\fn f() -> i32 { \\ i32(return 1) \\} - \\extern fn entry() { _ = f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { _ = f(); } , ".tmp_source.zig:2:8: error: unreachable code"); cases.add("invalid builtin fn", \\fn f() -> @bogus(foo) { \\} - \\extern fn entry() { _ = f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { _ = f(); } , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'"); cases.add("top level decl dependency loop", \\const a : @typeOf(b) = 0; \\const b : @typeOf(a) = 0; - \\extern fn entry() { + \\export fn entry() { \\ const c = a + b; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: 'a' depends on itself"); cases.add("noalias on non pointer param", \\fn f(noalias x: i32) {} - \\extern fn entry() { f(1234); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(1234); } , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter"); cases.add("struct init syntax for array", \\const foo = []u16{.x = 1024,}; - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); cases.add("type variables must be constant", \\var foo = u8; - \\extern fn entry() -> foo { + \\export fn entry() -> foo { \\ return 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant"); @@ -628,10 +521,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var Bar : i32 = undefined; \\} \\ - \\extern fn entry() { + \\export fn entry() { \\ f(1234); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:6: error: redefinition of 'Foo'", ".tmp_source.zig:1:1: note: previous definition is here", @@ -653,8 +545,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); cases.add("switch expression - duplicate enumeration prong", @@ -674,8 +565,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -697,8 +587,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -710,10 +599,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => true, \\ }; \\} - \\extern fn entry() { + \\export fn entry() { \\ f(1234); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression"); cases.add("switch expression - non exhaustive integer prongs", @@ -722,8 +610,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 0 => {}, \\ } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: switch must handle all possibilities"); @@ -736,8 +623,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 206 ... 255 => 3, \\ } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:6:9: error: duplicate switch value", ".tmp_source.zig:5:14: note: previous value is here"); @@ -749,16 +635,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\const y: u8 = 100; - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); cases.add("global variable initializer must be constant expression", \\extern fn foo() -> i32; \\const x = foo(); - \\extern fn entry() -> i32 { x } - \\comptime {@export("entry", entry);} + \\export fn entry() -> i32 { x } , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); cases.add("array concatenation with wrong type", @@ -766,8 +650,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const derp = usize(1234); \\const a = derp ++ "foo"; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); cases.add("non compile time array concatenation", @@ -775,14 +658,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ s ++ "foo" \\} \\var s: [10]u8 = undefined; - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); cases.add("@cImport with bogus include", \\const c = @cImport(@cInclude("bogus.h")); - \\extern fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } , ".tmp_source.zig:1:11: error: C import failed", ".h:1:10: note: 'bogus.h' file not found"); @@ -790,20 +671,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x = 3; \\const y = &x; \\fn foo() -> &const i32 { y } - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); cases.add("integer overflow error", \\const x : u8 = 300; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); cases.add("incompatible number literals", \\const x = 2 == 2.0; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); cases.add("missing function call param", @@ -829,15 +707,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const result = members[index](); \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); cases.add("missing function name and param name", \\fn () {} \\fn f(i32) {} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:1:1: error: missing function name", ".tmp_source.zig:2:6: error: missing parameter name"); @@ -847,20 +723,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn a() -> i32 {0} \\fn b() -> i32 {1} \\fn c() -> i32 {2} - \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); cases.add("extern function pointer mismatch", \\const fns = [](fn(i32)->i32){ a, b, c }; \\pub fn a(x: i32) -> i32 {x + 0} \\pub fn b(x: i32) -> i32 {x + 1} - \\extern fn c(x: i32) -> i32 {x + 2} - \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\export fn c(x: i32) -> i32 {x + 2} \\ - \\comptime {@export("entry", entry);} - \\comptime {@export("c", c);} + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); @@ -868,16 +740,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x : f64 = 1.0; \\const y : f32 = x; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); cases.add("colliding invalid top level functions", \\fn func() -> bogus {} \\fn func() -> bogus {} - \\extern fn entry() -> usize { @sizeOf(@typeOf(func)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } , ".tmp_source.zig:2:1: error: redefinition of 'func'", ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); @@ -885,8 +755,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("bogus compile var", \\const x = @import("builtin").bogus; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); @@ -897,8 +766,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\var global_var: usize = 1; \\fn get() -> usize { global_var } \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(Foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } , ".tmp_source.zig:5:21: error: unable to evaluate constant expression", ".tmp_source.zig:2:12: note: called from here", @@ -911,8 +779,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\}; \\const x = Foo {.field = 1} + Foo {.field = 2}; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); @@ -922,14 +789,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const int_x = u32(1) / u32(0); \\const float_x = f32(1.0) / f32(0.0); \\ - \\extern fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } - \\extern fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } - \\extern fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } - \\extern fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } - \\comptime {@export("entry1", entry1);} - \\comptime {@export("entry2", entry2);} - \\comptime {@export("entry3", entry3);} - \\comptime {@export("entry4", entry4);} + \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } + \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } + \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } , ".tmp_source.zig:1:21: error: division by zero is undefined", ".tmp_source.zig:2:25: error: division by zero is undefined", @@ -941,16 +804,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const foo = "a \\b"; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); cases.add("invalid comparison for function pointers", \\fn foo() {} \\const invalid = foo > foo; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(invalid)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); cases.add("generic function instance with non-constant expression", @@ -959,18 +820,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return foo(a, b); \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(test1)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); cases.add("goto jumping into block", - \\extern fn f() { + \\export fn f() { \\ { \\a_label: \\ } \\ goto a_label; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); cases.add("goto jumping past a defer", @@ -981,23 +840,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\fn derp(){} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); cases.add("assign null to non-nullable pointer", \\const a: &u8 = null; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); cases.add("indexing an array of size zero", \\const array = []u8{}; - \\extern fn foo() { + \\export fn foo() { \\ const pointer = &array[0]; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:27: error: index 0 outside array of size 0"); cases.add("compile time division by zero", @@ -1006,8 +862,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 1 / x \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: division by zero is undefined", ".tmp_source.zig:1:14: note: called from here"); @@ -1015,8 +870,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("branch on undefined value", \\const x = if (undefined) true else false; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:15: error: use of undefined value"); @@ -1026,8 +880,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return fibbonaci(x - 1) + fibbonaci(x - 2); \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } , ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", ".tmp_source.zig:3:21: note: called from here"); @@ -1035,8 +888,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@embedFile with bogus file", \\const resource = @embedFile("bogus.txt"); \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(resource)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); cases.add("non-const expression in struct literal outside function", @@ -1046,8 +898,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const a = Foo {.x = get_it()}; \\extern fn get_it() -> i32; \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); cases.add("non-const expression function call with struct return value outside function", @@ -1061,20 +912,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\var global_side_effect = false; \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:6:24: error: unable to evaluate constant expression", ".tmp_source.zig:4:17: note: called from here"); cases.add("undeclared identifier error should mark fn as impure", - \\extern fn foo() { + \\export fn foo() { \\ test_a_thing(); \\} \\fn test_a_thing() { \\ bad_fn_call(); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'"); cases.add("illegal comparison of types", @@ -1089,16 +938,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ *a == *b \\} \\ - \\extern fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } - \\extern fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } - \\comptime {@export("entry1", entry1);} - \\comptime {@export("entry2", entry2);} + \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } , ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); cases.add("non-const switch number literal", - \\extern fn foo() { + \\export fn foo() { \\ const x = switch (bar()) { \\ 1, 2 => 1, \\ 3, 4 => 2, @@ -1108,25 +955,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar() -> i32 { \\ 2 \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: unable to infer expression type"); cases.add("atomic orderings of cmpxchg - failure stricter than success", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn f() { + \\export fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success"); cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn f() { + \\export fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter"); cases.add("negation overflow in function evaluation", @@ -1135,8 +979,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ -x \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:5: error: negation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1147,8 +990,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a + b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1160,8 +1002,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a - b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1172,8 +1013,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a * b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1184,35 +1024,40 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @truncate(i8, x) \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); cases.add("%return in function with non error return type", - \\extern fn f() { + \\export fn f() { \\ %return something(); \\} \\fn something() -> %void { } - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); + cases.add("wrong return type for main", + \\pub fn main() { } + , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); + cases.add("invalid pointer for var type", \\extern fn ext() -> usize; \\var bytes: [ext()]u8 = undefined; - \\extern fn f() { + \\export fn f() { \\ for (bytes) |*b, i| { \\ *b = u8(i); \\ } \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:13: error: unable to evaluate constant expression"); cases.add("export function with comptime parameter", - \\extern fn foo(comptime x: i32, y: i32) -> i32{ + \\export fn foo(comptime x: i32, y: i32) -> i32{ \\ x + y \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("extern function with comptime parameter", @@ -1220,16 +1065,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() -> i32 { \\ foo(1, 2) \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("convert fixed size array to slice with invalid size", - \\extern fn f() { + \\export fn f() { \\ var array: [5]u8 = undefined; \\ var foo = ([]const u32)(array)[0]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch"); cases.add("non-pure function returns type", @@ -1247,11 +1090,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn function_with_return_type_type() { + \\export fn function_with_return_type_type() { \\ var list: List(i32) = undefined; \\ list.length = 10; \\} - \\comptime {@export("function_with_return_type_type", function_with_return_type_type);} , ".tmp_source.zig:3:7: error: unable to evaluate constant expression", ".tmp_source.zig:16:19: note: called from here"); @@ -1260,8 +1102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f(m: []const u8) { \\ m.copy(u8, self[0..], m); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); cases.add("wrong number of arguments for method fn call", @@ -1272,24 +1113,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\ foo.method(1, 2); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); cases.add("assign through constant pointer", - \\extern fn f() { + \\export fn f() { \\ var cstr = c"Hat"; \\ cstr[0] = 'W'; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("assign through constant slice", - \\extern fn f() { + \\export fn f() { \\ var cstr: []const u8 = "Hat"; \\ cstr[0] = 'W'; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("main function with bogus args type", @@ -1300,8 +1138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(blah: []u8) { \\ for (blah) { } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); cases.add("misspelled type with pointer only reference", @@ -1334,8 +1171,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); cases.add("method call with first arg type primitive", @@ -1349,12 +1185,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\}; \\ - \\extern fn f() { + \\export fn f() { \\ const derp = Foo.init(3); \\ \\ derp.init(); \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'"); cases.add("method call with first arg type wrong container", @@ -1378,11 +1213,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ field: i32, \\}; \\ - \\extern fn foo() { + \\export fn foo() { \\ var x = List.init(&global_allocator); \\ x.init(); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'"); cases.add("binary not on number literal", @@ -1390,18 +1224,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); cases.addCase({ const tc = cases.create("multiple files with private function error", \\const foo = @import("foo.zig"); \\ - \\extern fn callPrivFunction() { + \\export fn callPrivFunction() { \\ foo.privateFunction(); \\} - \\comptime {@export("callPrivFunction", callPrivFunction);} , ".tmp_source.zig:4:8: error: 'privateFunction' is private", "foo.zig:1:1: note: declared here"); @@ -1417,19 +1249,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const zero: i32 = 0; \\const a = zero{1}; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); cases.add("assign to constant field", \\const Foo = struct { \\ field: i32, \\}; - \\extern fn derp() { + \\export fn derp() { \\ const f = Foo {.field = 1234,}; \\ f.field = 0; \\} - \\comptime {@export("derp", derp);} , ".tmp_source.zig:6:13: error: cannot assign to constant"); cases.add("return from defer expression", @@ -1447,8 +1277,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return 0; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } , ".tmp_source.zig:4:11: error: cannot return from defer expression"); cases.add("attempt to access var args out of bounds", @@ -1460,8 +1289,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(i32(1234)) \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", ".tmp_source.zig:6:8: note: called from here"); @@ -1479,31 +1307,27 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(1, 2, 3, 4) \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(bar)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); cases.add("assign too big number to u16", - \\extern fn foo() { + \\export fn foo() { \\ var vga_mem: u16 = 0xB8000; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); cases.add("global variable alignment non power of 2", \\const some_data: [100]u8 align(3) = undefined; - \\extern fn entry() -> usize { @sizeOf(@typeOf(some_data)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); cases.add("function alignment non power of 2", \\extern fn foo() align(3); - \\extern fn entry() { foo() } - \\comptime {@export("entry", entry);} + \\export fn entry() { foo() } , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); cases.add("compile log", - \\extern fn foo() { + \\export fn foo() { \\ comptime bar(12, "hi"); \\} \\fn bar(a: i32, b: []const u8) { @@ -1511,7 +1335,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @compileLog("a", a, "b", b); \\ @compileLog("end"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: found compile log statement", ".tmp_source.zig:2:17: note: called from here", @@ -1535,8 +1358,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return *x; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); cases.add("referring to a struct that is invalid", @@ -1544,20 +1366,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Type: u8, \\}; \\ - \\extern fn foo() { + \\export fn foo() { \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); \\} \\ \\fn assert(ok: bool) { \\ if (!ok) unreachable; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:10:14: error: unable to evaluate constant expression", ".tmp_source.zig:6:20: note: called from here"); cases.add("control flow uses comptime var at runtime", - \\extern fn foo() { + \\export fn foo() { \\ comptime var i = 0; \\ while (i < 5) : (i += 1) { \\ bar(); @@ -1565,61 +1386,53 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\ \\fn bar() { } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime", ".tmp_source.zig:3:24: note: compile-time variable assigned here"); cases.add("ignored return value", - \\extern fn foo() { + \\export fn foo() { \\ bar(); \\} \\fn bar() -> i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:8: error: expression value is ignored"); cases.add("ignored assert-err-ok return value", - \\extern fn foo() { + \\export fn foo() { \\ %%bar(); \\} \\fn bar() -> %i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored statement value", - \\extern fn foo() { + \\export fn foo() { \\ 1; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored comptime statement value", - \\extern fn foo() { + \\export fn foo() { \\ comptime {1;} \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expression value is ignored"); cases.add("ignored comptime value", - \\extern fn foo() { + \\export fn foo() { \\ comptime 1; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored defered statement value", - \\extern fn foo() { + \\export fn foo() { \\ defer {1;} \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:12: error: expression value is ignored"); cases.add("ignored defered statement value", - \\extern fn foo() { + \\export fn foo() { \\ defer bar(); \\} \\fn bar() -> %i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: expression value is ignored"); cases.add("dereference an array", @@ -1630,8 +1443,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return (*out)[0..1]; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(pass)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); cases.add("pass const ptr to mutable ptr fn", @@ -1644,31 +1456,46 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return true; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); + cases.addCase({ + const tc = cases.create("export collision", + \\const foo = @import("foo.zig"); + \\ + \\export fn bar() -> usize { + \\ return foo.baz; + \\} + , + "foo.zig:1:8: error: exported symbol collision: 'bar'", + ".tmp_source.zig:3:8: note: other symbol here"); + + tc.addSourceFile("foo.zig", + \\export fn bar() {} + \\pub const baz = 1234; + ); + + tc + }); + cases.add("pass non-copyable type by value to function", \\const Point = struct { x: i32, y: i32, }; \\fn foo(p: Point) { } - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); cases.add("implicit cast from array to mutable slice", \\var global_array: [10]i32 = undefined; \\fn foo(param: []i32) {} - \\extern fn entry() { + \\export fn entry() { \\ foo(global_array); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'"); cases.add("ptrcast to non-pointer", - \\extern fn entry(a: &i32) -> usize { + \\export fn entry(a: &i32) -> usize { \\ return @ptrCast(usize, a); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); cases.add("too many error values to cast to small integer", @@ -1677,8 +1504,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(e: error) -> u2 { \\ return u2(e); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); cases.add("asm at compile time", @@ -1697,46 +1523,41 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("invalid member of builtin enum", \\const builtin = @import("builtin"); - \\extern fn entry() { + \\export fn entry() { \\ const foo = builtin.Arch.x86; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'"); cases.add("int to ptr of 0 bits", - \\extern fn foo() { + \\export fn foo() { \\ var x: usize = 0x1000; \\ var y: &void = @intToPtr(&void, x); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information"); cases.add("@fieldParentPtr - non struct", \\const Foo = i32; - \\extern fn foo(a: &i32) -> &Foo { + \\export fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'"); cases.add("@fieldParentPtr - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\extern fn foo(a: &i32) -> &Foo { + \\export fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'"); cases.add("@fieldParentPtr - field pointer is not pointer", \\const Foo = struct { \\ a: i32, \\}; - \\extern fn foo(a: i32) -> &Foo { + \\export fn foo(a: i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'"); cases.add("@fieldParentPtr - comptime field ptr not based on struct", @@ -1766,20 +1587,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@offsetOf - non struct", \\const Foo = i32; - \\extern fn foo() -> usize { + \\export fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:22: error: expected struct type, found 'i32'"); cases.add("@offsetOf - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\extern fn foo() -> usize { + \\export fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'"); cases.addExe("missing main fn in executable", @@ -1792,22 +1611,44 @@ pub fn addCases(cases: &tests.CompileErrorContext) { "error: 'main' is private", ".tmp_source.zig:1:1: note: declared here"); + cases.add("setting a section on an extern variable", + \\extern var foo: i32 section(".text2"); + \\export fn entry() -> i32 { + \\ return foo; + \\} + , + ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); + + cases.add("setting a section on a local variable", + \\export fn entry() -> i32 { + \\ var foo: i32 section(".text2") = 1234; + \\ return foo; + \\} + , + ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); + + cases.add("setting a section on an extern fn", + \\extern fn foo() section(".text2"); + \\export fn entry() { + \\ foo(); + \\} + , + ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); + cases.add("returning address of local variable - simple", - \\extern fn foo() -> &i32 { + \\export fn foo() -> &i32 { \\ var a: i32 = undefined; \\ return &a; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:13: error: function returns address of local variable"); cases.add("returning address of local variable - phi", - \\extern fn foo(c: bool) -> &i32 { + \\export fn foo(c: bool) -> &i32 { \\ var a: i32 = undefined; \\ var b: i32 = undefined; \\ return if (c) &a else &b; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:12: error: function returns address of local variable"); @@ -1836,61 +1677,55 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:5:9: note: previous definition is here"); cases.add("while expected bool, got nullable", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) {} \\} \\fn bar() -> ?i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); cases.add("while expected bool, got error union", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) {} \\} \\fn bar() -> %i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); cases.add("while expected nullable, got bool", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> bool { true } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); cases.add("while expected nullable, got error union", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> %i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); cases.add("while expected error union, got bool", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> bool { true } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); cases.add("while expected error union, got nullable", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> ?i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); cases.add("inline fn calls itself indirectly", - \\extern fn foo() { + \\export fn foo() { \\ bar(); \\} \\inline fn bar() { @@ -1902,33 +1737,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ quux(); \\} \\extern fn quux(); - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("save reference to inline function", - \\extern fn foo() { + \\export fn foo() { \\ quux(@ptrToInt(bar)); \\} \\inline fn bar() { } \\extern fn quux(usize); - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("signed integer division", - \\extern fn foo(a: i32, b: i32) -> i32 { + \\export fn foo(a: i32, b: i32) -> i32 { \\ a / b \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); cases.add("signed integer remainder division", - \\extern fn foo(a: i32, b: i32) -> i32 { + \\export fn foo(a: i32, b: i32) -> i32 { \\ a % b \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); @@ -1967,65 +1798,59 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); cases.add("@setDebugSafety twice for same scope", - \\extern fn foo() { + \\export fn foo() { \\ @setDebugSafety(this, false); \\ @setDebugSafety(this, false); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: debug safety set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setFloatMode twice for same scope", - \\extern fn foo() { + \\export fn foo() { \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: float mode set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("array access of type", - \\extern fn foo() { + \\export fn foo() { \\ var b: u8[40] = undefined; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: array access of non-array type 'type'"); cases.add("cannot break out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ while (true) { \\ defer { \\ break; \\ } \\ } \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot break out of defer expression"); cases.add("cannot continue out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ while (true) { \\ defer { \\ continue; \\ } \\ } \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); cases.add("cannot goto out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ defer { \\ goto label; \\ }; \\label: \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); @@ -2059,10 +1884,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const bar = baz + foo; \\const baz = 1; \\ - \\extern fn entry() -> i32 { + \\export fn entry() -> i32 { \\ return bar; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: aoeu", ".tmp_source.zig:3:19: note: referenced here", @@ -2075,10 +1899,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\var foo: Foo = undefined; \\ - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(@typeOf(foo.x)); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: struct 'Foo' contains itself"); @@ -2097,18 +1920,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: float literal out of range of any type"); cases.add("explicit cast float literal to integer when there is a fraction component", - \\extern fn entry() -> i32 { + \\export fn entry() -> i32 { \\ i32(12.34) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); cases.add("non pointer given to @ptrToInt", - \\extern fn entry(x: i32) -> usize { + \\export fn entry(x: i32) -> usize { \\ @ptrToInt(x) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:15: error: expected pointer, found 'i32'"); @@ -2127,27 +1948,24 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits"); cases.add("shifting without int type or comptime known", - \\extern fn entry(x: u8) -> u8 { + \\export fn entry(x: u8) -> u8 { \\ return 0x11 << x; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known"); cases.add("shifting RHS is log2 of LHS int bit width", - \\extern fn entry(x: u8, y: u8) -> u8 { + \\export fn entry(x: u8, y: u8) -> u8 { \\ return x << y; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'"); cases.add("globally shadowing a primitive type", \\const u16 = @intType(false, 8); - \\extern fn entry() { + \\export fn entry() { \\ const a: u16 = 300; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: declaration shadows type 'u16'"); @@ -2157,7 +1975,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ bar(&foo.b); \\} @@ -2165,7 +1983,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &u32) { \\ *x += 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'"); @@ -2175,7 +1992,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ foo.b += 1; \\ bar((&foo.b)[0..1]); @@ -2184,61 +2001,55 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: []u32) { \\ x[0] += 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'"); cases.add("increase pointer alignment in @ptrCast", - \\extern fn entry() -> u32 { + \\export fn entry() -> u32 { \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04}; \\ const ptr = @ptrCast(&u32, &bytes[0]); \\ return *ptr; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:17: error: cast increases pointer alignment", ".tmp_source.zig:3:38: note: '&u8' has alignment 1", ".tmp_source.zig:3:27: note: '&u32' has alignment 4"); cases.add("increase pointer alignment in slice resize", - \\extern fn entry() -> u32 { + \\export fn entry() -> u32 { \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04}; \\ return ([]u32)(bytes[0..])[0]; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: cast increases pointer alignment", ".tmp_source.zig:3:19: note: '[]u8' has alignment 1", ".tmp_source.zig:3:19: note: '[]u32' has alignment 4"); cases.add("@alignCast expects pointer or slice", - \\extern fn entry() { + \\export fn entry() { \\ @alignCast(4, u32(3)) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); cases.add("passing an under-aligned function pointer", - \\extern fn entry() { + \\export fn entry() { \\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234); \\} \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { \\ if (ptr() != answer) unreachable; \\} \\fn alignedSmall() align(4) -> i32 { 1234 } - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); cases.add("passing a not-aligned-enough pointer to cmpxchg", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn entry() -> bool { + \\export fn entry() -> bool { \\ var x: i32 align(1) = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} \\ return x == 5678; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1"); @@ -2264,18 +2075,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); \\extern fn bar(d: &Derp); - \\extern fn foo() { + \\export fn foo() { \\ const x = u8(1); \\ bar(@ptrCast(&c_void, &x)); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'"); cases.add("non-const variables of things that require const variables", \\const Opaque = @OpaqueType(); \\ - \\extern fn entry(opaque: &Opaque) { + \\export fn entry(opaque: &Opaque) { \\ var m2 = &2; \\ const y: u32 = *m2; \\ @@ -2295,7 +2105,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = struct { \\ fn bar(self: &const Foo) {} \\}; - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime", ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", @@ -2310,14 +2119,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:17:4: error: unreachable code"); cases.add("wrong types given to atomic order args in cmpxchg", - \\extern fn entry() { + \\export fn entry() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {} \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); + cases.add("wrong types given to @export", + \\extern fn entry() { } + \\comptime { + \\ @export("entry", entry, u32(1234)); + \\} + , + ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'"); + cases.add("struct with invalid field", \\const std = @import("std"); \\const Allocator = std.mem.Allocator; @@ -2336,13 +2152,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ }, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ const a = MdNode.Header { \\ .text = MdText.init(&std.debug.global_allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); @@ -2354,39 +2169,35 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:5: error: @setAlignStack outside function"); cases.add("@setAlignStack in naked function", - \\nakedcc fn entry() { + \\export nakedcc fn entry() { \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); cases.add("@setAlignStack in inline function", - \\extern fn entry() { + \\export fn entry() { \\ foo(); \\} \\inline fn foo() { \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); cases.add("@setAlignStack set twice", - \\extern fn entry() { + \\export fn entry() { \\ @setAlignStack(16); \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setAlignStack too big", - \\extern fn entry() { + \\export fn entry() { \\ @setAlignStack(511 + 1); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); @@ -2417,7 +2228,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ LinkLibC, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ const tests = []TestCase { \\ Free("001"), \\ Free("002"), @@ -2432,14 +2243,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\ } \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); cases.add("field access of opaque type", \\const MyType = @OpaqueType(); \\ - \\extern fn entry() -> bool { + \\export fn entry() -> bool { \\ var x: i32 = 1; \\ return bar(@ptrCast(&MyType, &x)); \\} @@ -2447,7 +2257,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &MyType) -> bool { \\ return x.blah; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); @@ -2551,11 +2360,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); cases.add("calling var args extern function, passing array instead of pointer", - \\extern fn entry() { + \\export fn entry() { \\ foo("hello"); \\} \\pub extern fn foo(format: &const u8, ...); - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); @@ -2570,10 +2378,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() { + \\export fn entry() { \\ var allocator: ContextAllocator = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:25: error: aoeu", ".tmp_source.zig:1:36: note: called from here", @@ -2588,10 +2395,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Five, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = Small.One; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'"); @@ -2602,10 +2408,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Three, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = Small.One; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: expected integer, found 'f32'"); @@ -2617,10 +2422,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x: u2 = Small.Two; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'"); @@ -2632,10 +2436,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = u3(Small.Two); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'"); @@ -2647,11 +2450,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var y = u3(3); \\ var x = Small(y); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'"); @@ -2663,10 +2465,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var y = Small.Two; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'"); @@ -2674,10 +2475,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = struct { \\ A: i32 = 20, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: MultipleChoice = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: enums, not structs, support field assignment"); @@ -2685,29 +2485,26 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = union { \\ A: i32 = 20, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: MultipleChoice = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: non-enum union field assignment", ".tmp_source.zig:1:24: note: consider 'union(enum)' here"); cases.add("enum with 0 fields", \\const Foo = enum {}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: enums must have 1 or more fields"); cases.add("union with 0 fields", \\const Foo = union {}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: unions must have 1 or more fields"); @@ -2719,10 +2516,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = MultipleChoice.C; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2737,10 +2533,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A: i32, \\ B: f64, \\}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Payload); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:17: error: enum field missing: 'C'", ".tmp_source.zig:4:5: note: declared here"); @@ -2749,10 +2544,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:24: error: union 'Foo' has no tag", ".tmp_source.zig:1:13: note: consider 'union(enum)' here"); @@ -2761,10 +2555,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(enum(f32)) { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'"); @@ -2772,10 +2565,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(u32) { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'"); @@ -2787,10 +2579,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = MultipleChoice { .C = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2807,10 +2598,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ C: bool, \\ D: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload {.A = 1234}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:5: error: enum field not found: 'D'", ".tmp_source.zig:1:16: note: enum declared here"); @@ -2821,10 +2611,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var b = Letter.B; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types", ".tmp_source.zig:1:16: note: consider 'union(enum)' here"); @@ -2833,10 +2622,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = struct { \\ A, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Letter { .A = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: struct field missing type"); @@ -2844,10 +2632,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = extern union { \\ A, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Letter { .A = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: union field missing type"); @@ -2862,10 +2649,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); @@ -2880,10 +2666,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); @@ -2893,7 +2678,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const a = Payload { .A = { 1234 } }; \\ foo(a); \\} @@ -2903,7 +2688,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => unreachable, \\ } \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:13: error: switch on union which has no attached enum", ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); @@ -2913,10 +2697,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A = 10, \\ B = 11, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = Foo(0); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", ".tmp_source.zig:1:13: note: 'Foo' declared here"); @@ -2928,10 +2711,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: Value = Letter.A; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", ".tmp_source.zig:3:5: note: field 'A' declared here"); @@ -2943,36 +2725,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ foo(Letter.A); \\} \\fn foo(l: Letter) { \\ var x: Value = l; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); - - cases.addCase({ - const tc = cases.create("export collision", - \\const foo = @import("foo.zig"); - \\ - \\comptime {@export("bar", bar);} - \\extern fn bar() -> usize { - \\ return foo.baz; - \\} - , - "foo.zig:2:11: error: exported symbol collision: 'bar'", - ".tmp_source.zig:3:11: note: other symbol is here"); - - tc.addSourceFile("foo.zig", - \\extern fn bar() {} - \\comptime {@export("bar", bar);} - \\pub const baz = 1234; - ); - - tc - }); - } diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index a3058e58ed..c1faa015c6 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -2,9 +2,6 @@ pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } fn bar() -> %void {} -comptime { - @export("foo", foo); -} -extern fn foo() { +export fn foo() { %%bar(); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 01f6622a71..aff2140f8d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -26,7 +26,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a < 0 ? -a : a; \\} , - \\pub fn abs(a: c_int) -> c_int { + \\export fn abs(a: c_int) -> c_int { \\ return if (a < 0) -a else a; \\} ); @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn foo1(_arg_a: c_uint) -> c_uint { + \\pub export fn foo1(_arg_a: c_uint) -> c_uint { \\ var a = _arg_a; \\ a +%= 1; \\ return a; \\} - \\pub fn foo2(_arg_a: c_int) -> c_int { + \\pub export fn foo2(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ a += 1; \\ return a; @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\pub fn log2(_arg_a: c_uint) -> c_int { + \\pub export fn log2(_arg_a: c_uint) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if (a < b) return b; \\ if (a < b) return b else return a; \\} @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if (a == b) return a; \\ if (a != b) return b; \\ return a; @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = a % b; \\} , - \\pub fn s(a: c_int, b: c_int) -> c_int { + \\pub export fn s(a: c_int, b: c_int) -> c_int { \\ var c: c_int; \\ c = (a + b); \\ c = (a - b); @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = @divTrunc(a, b); \\ c = @rem(a, b); \\} - \\pub fn u(a: c_uint, b: c_uint) -> c_uint { + \\pub export fn u(a: c_uint, b: c_uint) -> c_uint { \\ var c: c_uint; \\ c = (a +% b); \\ c = (a -% b); @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (a & b) ^ (a | b); \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ return (a & b) ^ (a | b); \\} ); @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if ((a < b) or (a == b)) return b; \\ if ((a >= b) and (a == b)) return a; \\ return a; @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a = tmp; \\} , - \\pub fn max(_arg_a: c_int) -> c_int { + \\pub export fn max(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ var tmp: c_int; \\ tmp = a; @@ -472,7 +472,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = b = a; \\} , - \\pub fn max(a: c_int) { + \\pub export fn max(a: c_int) { \\ var b: c_int; \\ var c: c_int; \\ c = { @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\pub fn log2(_arg_a: u32) -> c_int { + \\pub export fn log2(_arg_a: u32) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\void foo(void) { bar(); } , \\pub fn bar() {} - \\pub fn foo() { + \\pub export fn foo() { \\ bar(); \\} ); @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub const struct_Foo = extern struct { \\ field: c_int, \\}; - \\pub fn read_field(foo: ?&struct_Foo) -> c_int { + \\pub export fn read_field(foo: ?&struct_Foo) -> c_int { \\ return (??foo).field; \\} ); @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ ;;;;; \\} , - \\pub fn foo() {} + \\pub export fn foo() {} ); cases.add("undefined array global", @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} , \\pub var array: [100]c_int = undefined; - \\pub fn foo(index: c_int) -> c_int { + \\pub export fn foo(index: c_int) -> c_int { \\ return array[index]; \\} ); @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (int)a; \\} , - \\pub fn float_to_int(a: f32) -> c_int { + \\pub export fn float_to_int(a: f32) -> c_int { \\ return c_int(a); \\} ); @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return x; \\} , - \\pub fn foo(x: ?&c_ushort) -> ?&c_void { + \\pub export fn foo(x: ?&c_ushort) -> ?&c_void { \\ return @ptrCast(?&c_void, x); \\} ); @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return sizeof(int); \\} , - \\pub fn size_of() -> usize { + \\pub export fn size_of() -> usize { \\ return @sizeOf(c_int); \\} ); @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 0; \\} , - \\pub fn foo() -> ?&c_int { + \\pub export fn foo() -> ?&c_int { \\ return null; \\} ); @@ -612,7 +612,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 1, 2; \\} , - \\pub fn foo() -> c_int { + \\pub export fn foo() -> c_int { \\ return { \\ _ = 1; \\ 2 @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (1 << 2) >> 1; \\} , - \\pub fn foo() -> c_int { + \\pub export fn foo() -> c_int { \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); \\} ); @@ -643,7 +643,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_int = 0; \\ a += { \\ const _ref = &a; @@ -701,7 +701,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_uint = c_uint(0); \\ a +%= { \\ const _ref = &a; @@ -771,7 +771,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = u--; \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -819,7 +819,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = --u; \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ while (b != 0); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_int = 2; \\ while (true) { \\ a -= 1; @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ baz(); \\} , - \\pub fn foo() {} - \\pub fn baz() {} - \\pub fn bar() { + \\pub export fn foo() {} + \\pub export fn baz() {} + \\pub export fn bar() { \\ var f: ?extern fn() = foo; \\ (??f)(); \\ (??f)(); @@ -901,7 +901,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ *x = 1; \\} , - \\pub fn foo(x: ?&c_int) { + \\pub export fn foo(x: ?&c_int) { \\ (*??x) = 1; \\} ); -- cgit v1.2.3 From 8bc523219c66427951e5339550502871547f2138 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Dec 2017 22:55:24 -0500 Subject: add labeled loops, labeled break, labeled continue. remove goto closes #346 closes #630 regression: translate-c can no longer translate switch statements. after #629 we can ressurect and modify the code to utilize arbitrarily returning from blocks. --- doc/langref.html.in | 18 ++--- src/all_types.hpp | 15 ++-- src/analyze.cpp | 10 ++- src/ast_render.cpp | 32 ++++---- src/ir.cpp | 183 ++++++++----------------------------------- src/parser.cpp | 203 +++++++++++++++++++++++++----------------------- src/translate_c.cpp | 184 ++----------------------------------------- std/elf.zig | 6 +- std/os/index.zig | 146 +++++++++++++++++----------------- test/behavior.zig | 1 - test/cases/for.zig | 34 ++++++++ test/cases/goto.zig | 37 --------- test/cases/while.zig | 27 +++++++ test/compile_errors.zig | 51 +++++------- test/translate_c.zig | 80 ------------------- 15 files changed, 339 insertions(+), 688 deletions(-) delete mode 100644 test/cases/goto.zig (limited to 'src/ast_render.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index e17e1ecd8f..faba4f8b10 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5847,11 +5847,9 @@ ParamDeclList = "(" list(ParamDecl, ",") ")" ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") -Block = "{" many(Statement) option(Expression) "}" +Block = option(Symbol ":") "{" many(Statement) option(Expression) "}" -Statement = Label | LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" - -Label = Symbol ":" +Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" TypeExpr = PrefixOpExpression | "var" @@ -5891,13 +5889,13 @@ SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" option("*") Sy SwitchItem = Expression | (Expression "..." Expression) -ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) +ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression ReturnExpression = option("%") "return" option(Expression) -BreakExpression = "break" option(Expression) +BreakExpression = "break" option(":" Symbol) option(Expression) Defer(body) = option("%") "defer" body @@ -5907,7 +5905,7 @@ TryExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body)) -WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) +WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) BoolAndExpression = ComparisonExpression "and" BoolAndExpression | ComparisonExpression @@ -5955,15 +5953,13 @@ StructLiteralField = "." Symbol "=" Expression PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr -GotoExpression = "goto" Symbol - GroupedExpression = "(" Expression ")" -KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" +KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" ContainerDecl = option("extern" | "packed") ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) diff --git a/src/all_types.hpp b/src/all_types.hpp index 28477c8107..87541bb918 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -386,8 +386,6 @@ enum NodeType { NodeTypeSwitchExpr, NodeTypeSwitchProng, NodeTypeSwitchRange, - NodeTypeLabel, - NodeTypeGoto, NodeTypeCompTime, NodeTypeBreak, NodeTypeContinue, @@ -452,6 +450,7 @@ struct AstNodeParamDecl { }; struct AstNodeBlock { + Buf *name; ZigList statements; bool last_statement_is_result_expression; }; @@ -662,6 +661,7 @@ struct AstNodeTestExpr { }; struct AstNodeWhileExpr { + Buf *name; AstNode *condition; Buf *var_symbol; bool var_is_ptr; @@ -673,6 +673,7 @@ struct AstNodeWhileExpr { }; struct AstNodeForExpr { + Buf *name; AstNode *array_expr; AstNode *elem_node; // always a symbol AstNode *index_node; // always a symbol, might be null @@ -704,11 +705,6 @@ struct AstNodeLabel { Buf *name; }; -struct AstNodeGoto { - Buf *name; - bool is_inline; -}; - struct AstNodeCompTime { AstNode *expr; }; @@ -836,11 +832,14 @@ struct AstNodeBoolLiteral { }; struct AstNodeBreakExpr { + Buf *name; AstNode *expr; // may be null }; struct AstNodeContinueExpr { + Buf *name; }; + struct AstNodeUnreachableExpr { }; @@ -886,7 +885,6 @@ struct AstNode { AstNodeSwitchProng switch_prong; AstNodeSwitchRange switch_range; AstNodeLabel label; - AstNodeGoto goto_expr; AstNodeCompTime comptime_expr; AstNodeAsmExpr asm_expr; AstNodeFieldAccessExpr field_access_expr; @@ -1741,6 +1739,7 @@ struct ScopeCImport { struct ScopeLoop { Scope base; + Buf *name; IrBasicBlock *break_block; IrBasicBlock *continue_block; IrInstruction *is_comptime; diff --git a/src/analyze.cpp b/src/analyze.cpp index d6719cf52c..23301cc4de 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -144,9 +144,15 @@ ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent) { } ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) { - assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr); ScopeLoop *scope = allocate(1); init_scope(&scope->base, ScopeIdLoop, node, parent); + if (node->type == NodeTypeWhileExpr) { + scope->name = node->data.while_expr.name; + } else if (node->type == NodeTypeForExpr) { + scope->name = node->data.for_expr.name; + } else { + zig_unreachable(); + } return scope; } @@ -2916,8 +2922,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeSwitchExpr: case NodeTypeSwitchProng: case NodeTypeSwitchRange: - case NodeTypeLabel: - case NodeTypeGoto: case NodeTypeBreak: case NodeTypeContinue: case NodeTypeUnreachable: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index c22c16d90a..e64a19d42d 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -215,10 +215,6 @@ static const char *node_type_str(NodeType node_type) { return "SwitchProng"; case NodeTypeSwitchRange: return "SwitchRange"; - case NodeTypeLabel: - return "Label"; - case NodeTypeGoto: - return "Goto"; case NodeTypeCompTime: return "CompTime"; case NodeTypeBreak: @@ -391,7 +387,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { switch (node->type) { case NodeTypeSwitchProng: case NodeTypeSwitchRange: - case NodeTypeLabel: case NodeTypeStructValueField: zig_unreachable(); case NodeTypeRoot: @@ -470,6 +465,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { break; } case NodeTypeBlock: + if (node->data.block.name != nullptr) { + fprintf(ar->f, "%s: ", buf_ptr(node->data.block.name)); + } if (node->data.block.statements.length == 0) { fprintf(ar->f, "{}"); break; @@ -478,13 +476,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { ar->indent += ar->indent_size; for (size_t i = 0; i < node->data.block.statements.length; i += 1) { AstNode *statement = node->data.block.statements.at(i); - if (statement->type == NodeTypeLabel) { - ar->indent -= ar->indent_size; - print_indent(ar); - fprintf(ar->f, "%s:\n", buf_ptr(statement->data.label.name)); - ar->indent += ar->indent_size; - continue; - } print_indent(ar); render_node_grouped(ar, statement); if (!(i == node->data.block.statements.length - 1 && @@ -515,6 +506,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeBreak: { fprintf(ar->f, "break"); + if (node->data.break_expr.name != nullptr) { + fprintf(ar->f, " :%s", buf_ptr(node->data.break_expr.name)); + } if (node->data.break_expr.expr) { fprintf(ar->f, " "); render_node_grouped(ar, node->data.break_expr.expr); @@ -828,6 +822,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeWhileExpr: { + if (node->data.while_expr.name != nullptr) { + fprintf(ar->f, "%s: ", buf_ptr(node->data.while_expr.name)); + } const char *inline_str = node->data.while_expr.is_inline ? "inline " : ""; fprintf(ar->f, "%swhile (", inline_str); render_node_grouped(ar, node->data.while_expr.condition); @@ -957,11 +954,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "}"); break; } - case NodeTypeGoto: - { - fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name)); - break; - } case NodeTypeCompTime: { fprintf(ar->f, "comptime "); @@ -970,6 +962,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeForExpr: { + if (node->data.for_expr.name != nullptr) { + fprintf(ar->f, "%s: ", buf_ptr(node->data.for_expr.name)); + } const char *inline_str = node->data.for_expr.is_inline ? "inline " : ""; fprintf(ar->f, "%sfor (", inline_str); render_node_grouped(ar, node->data.for_expr.array_expr); @@ -995,6 +990,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeContinue: { fprintf(ar->f, "continue"); + if (node->data.continue_expr.name != nullptr) { + fprintf(ar->f, " :%s", buf_ptr(node->data.continue_expr.name)); + } break; } case NodeTypeUnreachable: diff --git a/src/ir.cpp b/src/ir.cpp index db919350d1..d3dd58aaff 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3511,29 +3511,6 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s return var; } -static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) { - while (scope) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - auto entry = block_scope->label_table.maybe_get(name); - if (entry) - return entry->value; - } - scope = scope->parent; - } - - return nullptr; -} - -static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) { - while (scope) { - if (scope->id == ScopeIdBlock) - return (ScopeBlock *)scope; - scope = scope->parent; - } - return nullptr; -} - static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) { assert(block_node->type == NodeTypeBlock); @@ -3557,38 +3534,6 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { AstNode *statement_node = block_node->data.block.statements.at(i); - if (statement_node->type == NodeTypeLabel) { - Buf *label_name = statement_node->data.label.name; - IrBasicBlock *label_block = ir_build_basic_block(irb, child_scope, buf_ptr(label_name)); - LabelTableEntry *label = allocate(1); - label->decl_node = statement_node; - label->bb = label_block; - irb->exec->all_labels.append(label); - - LabelTableEntry *existing_label = find_label(irb->exec, child_scope, label_name); - if (existing_label) { - ErrorMsg *msg = add_node_error(irb->codegen, statement_node, - buf_sprintf("duplicate label name '%s'", buf_ptr(label_name))); - add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here")); - return irb->codegen->invalid_instruction; - } else { - ScopeBlock *scope_block = find_block_scope(irb->exec, child_scope); - scope_block->label_table.put(label_name, label); - } - - if (!is_continuation_unreachable) { - // fall through into new labeled basic block - IrInstruction *is_comptime = ir_mark_gen(ir_build_const_bool(irb, child_scope, statement_node, - ir_should_inline(irb->exec, child_scope))); - ir_mark_gen(ir_build_br(irb, child_scope, statement_node, label_block, is_comptime)); - } - ir_set_cursor_at_end(irb, label_block); - - // a label is an entry point - is_continuation_unreachable = false; - continue; - } - IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); is_continuation_unreachable = instr_is_unreachable(statement_value); if (is_continuation_unreachable) { @@ -6000,22 +5945,6 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); } -static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeGoto); - - // make a placeholder unreachable statement and a note to come back and - // replace the instruction with a branch instruction - IrGotoItem *goto_item = irb->exec->goto_list.add_one(); - goto_item->bb = irb->current_basic_block; - goto_item->instruction_index = irb->current_basic_block->instruction_list.length; - goto_item->source_node = node; - goto_item->scope = scope; - - // we don't know if we need to generate defer expressions yet - // we do that later when we find out which label we're jumping to. - return ir_build_unreachable(irb, scope, node); -} - static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { assert(node->type == NodeTypeCompTime); @@ -6033,16 +5962,28 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode * Scope *search_scope = break_scope; ScopeLoop *loop_scope; + bool saw_any_loop_scope = false; for (;;) { if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); - return irb->codegen->invalid_instruction; + if (saw_any_loop_scope) { + add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.break_expr.name))); + return irb->codegen->invalid_instruction; + } else { + add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); + return irb->codegen->invalid_instruction; + } } else if (search_scope->id == ScopeIdDeferExpr) { add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); return irb->codegen->invalid_instruction; } else if (search_scope->id == ScopeIdLoop) { - loop_scope = (ScopeLoop *)search_scope; - break; + ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; + saw_any_loop_scope = true; + if (node->data.break_expr.name == nullptr || + (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) + { + loop_scope = this_loop_scope; + break; + } } search_scope = search_scope->parent; } @@ -6081,16 +6022,28 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast Scope *search_scope = continue_scope; ScopeLoop *loop_scope; + bool saw_any_loop_scope = false; for (;;) { if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); - return irb->codegen->invalid_instruction; + if (saw_any_loop_scope) { + add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); + return irb->codegen->invalid_instruction; + } else { + add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); + return irb->codegen->invalid_instruction; + } } else if (search_scope->id == ScopeIdDeferExpr) { add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); return irb->codegen->invalid_instruction; } else if (search_scope->id == ScopeIdLoop) { - loop_scope = (ScopeLoop *)search_scope; - break; + ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; + saw_any_loop_scope = true; + if (node->data.continue_expr.name == nullptr || + (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) + { + loop_scope = this_loop_scope; + break; + } } search_scope = search_scope->parent; } @@ -6332,7 +6285,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSwitchProng: case NodeTypeSwitchRange: case NodeTypeStructField: - case NodeTypeLabel: case NodeTypeFnDef: case NodeTypeFnDecl: case NodeTypeErrorValueDecl: @@ -6396,8 +6348,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); - case NodeTypeGoto: - return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); case NodeTypeCompTime: return ir_gen_comptime(irb, scope, node, lval); case NodeTypeErrorType: @@ -6432,70 +6382,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { return ir_gen_node_extra(irb, node, scope, LVAL_NONE); } -static bool ir_goto_pass2(IrBuilder *irb) { - for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { - IrGotoItem *goto_item = &irb->exec->goto_list.at(i); - AstNode *source_node = goto_item->source_node; - - // Since a goto will always end a basic block, we move the "current instruction" - // index back to over the placeholder unreachable instruction and begin overwriting - irb->current_basic_block = goto_item->bb; - irb->current_basic_block->instruction_list.resize(goto_item->instruction_index); - - Buf *label_name = source_node->data.goto_expr.name; - - // Search up the scope until we find one of these things: - // * A block scope with the label in it => OK - // * A defer expression scope => error, error, cannot leave defer expression - // * Top level scope => error, didn't find label - - LabelTableEntry *label; - Scope *search_scope = goto_item->scope; - for (;;) { - if (search_scope == nullptr) { - add_node_error(irb->codegen, source_node, - buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); - return false; - } else if (search_scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)search_scope; - auto entry = block_scope->label_table.maybe_get(label_name); - if (entry) { - label = entry->value; - break; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(irb->codegen, source_node, - buf_sprintf("cannot goto out of defer expression")); - return false; - } - search_scope = search_scope->parent; - } - - label->used = true; - - IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node, - ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline); - if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false)) { - add_node_error(irb->codegen, source_node, - buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); - return false; - } - ir_build_br(irb, goto_item->scope, source_node, label->bb, is_comptime); - } - - for (size_t i = 0; i < irb->exec->all_labels.length; i += 1) { - LabelTableEntry *label = irb->exec->all_labels.at(i); - if (!label->used) { - add_node_error(irb->codegen, label->decl_node, - buf_sprintf("label '%s' defined but not used", - buf_ptr(label->decl_node->data.label.name))); - return false; - } - } - - return true; -} - static void invalidate_exec(IrExecutable *exec) { if (exec->invalid) return; @@ -6532,11 +6418,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_mark_gen(ir_build_return(irb, scope, result->source_node, result)); } - if (!ir_goto_pass2(irb)) { - invalidate_exec(ir_executable); - return false; - } - return true; } diff --git a/src/parser.cpp b/src/parser.cpp index 579fe85f3b..b5fdd681e8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -632,27 +632,6 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m return node; } -/* -GotoExpression = "goto" Symbol -*/ -static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *goto_token = &pc->tokens->at(*token_index); - if (goto_token->id == TokenIdKeywordGoto) { - *token_index += 1; - } else if (mandatory) { - ast_expect_token(pc, goto_token, TokenIdKeywordGoto); - zig_unreachable(); - } else { - return nullptr; - } - - AstNode *node = ast_create_node(pc, NodeTypeGoto, goto_token); - - Token *dest_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); - node->data.goto_expr.name = token_buf(dest_symbol); - return node; -} - /* CompTimeExpression(body) = "comptime" body */ @@ -676,8 +655,8 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b } /* -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl -KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) +KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -721,6 +700,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo } else if (token->id == TokenIdKeywordContinue) { AstNode *node = ast_create_node(pc, NodeTypeContinue, token); *token_index += 1; + Token *maybe_colon_token = &pc->tokens->at(*token_index); + if (maybe_colon_token->id == TokenIdColon) { + *token_index += 1; + Token *name = ast_eat_token(pc, token_index, TokenIdSymbol); + node->data.continue_expr.name = token_buf(name); + } return node; } else if (token->id == TokenIdKeywordUndefined) { AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); @@ -770,10 +755,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo return node; } - AstNode *goto_node = ast_parse_goto_expr(pc, token_index, false); - if (goto_node) - return goto_node; - AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); if (grouped_expr_node) { return grouped_expr_node; @@ -1488,7 +1469,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) { } /* -BreakExpression : "break" option(Expression) +BreakExpression = "break" option(":" Symbol) option(Expression) */ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { Token *token = &pc->tokens->at(*token_index); @@ -1498,8 +1479,15 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) { } else { return nullptr; } - AstNode *node = ast_create_node(pc, NodeTypeBreak, token); + + Token *maybe_colon_token = &pc->tokens->at(*token_index); + if (maybe_colon_token->id == TokenIdColon) { + *token_index += 1; + Token *name = ast_eat_token(pc, token_index, TokenIdSymbol); + node->data.break_expr.name = token_buf(name); + } + node->data.break_expr.expr = ast_parse_expression(pc, token_index, false); return node; @@ -1678,35 +1666,53 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, size_t *token_index, bo } /* -WhileExpression(body) = option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) +WhileExpression(body) = option(Symbol ":") option("inline") "while" "(" Expression ")" option("|" option("*") Symbol "|") option(":" "(" Expression ")") body option("else" option("|" Symbol "|") BlockExpression(body)) */ static AstNode *ast_parse_while_expr(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *first_token = &pc->tokens->at(*token_index); - Token *while_token; + size_t orig_token_index = *token_index; - bool is_inline; - if (first_token->id == TokenIdKeywordInline) { - while_token = &pc->tokens->at(*token_index + 1); - if (while_token->id == TokenIdKeywordWhile) { - is_inline = true; - *token_index += 2; + Token *name_token = nullptr; + Token *token = &pc->tokens->at(*token_index); + + if (token->id == TokenIdSymbol) { + *token_index += 1; + Token *colon_token = &pc->tokens->at(*token_index); + if (colon_token->id == TokenIdColon) { + *token_index += 1; + name_token = token; + token = &pc->tokens->at(*token_index); } else if (mandatory) { - ast_expect_token(pc, while_token, TokenIdKeywordWhile); + ast_expect_token(pc, colon_token, TokenIdColon); zig_unreachable(); } else { + *token_index = orig_token_index; return nullptr; } - } else if (first_token->id == TokenIdKeywordWhile) { - while_token = first_token; - is_inline = false; + } + + bool is_inline = false; + if (token->id == TokenIdKeywordInline) { + is_inline = true; + *token_index += 1; + token = &pc->tokens->at(*token_index); + } + + Token *while_token; + if (token->id == TokenIdKeywordWhile) { + while_token = token; *token_index += 1; } else if (mandatory) { - ast_expect_token(pc, first_token, TokenIdKeywordWhile); + ast_expect_token(pc, token, TokenIdKeywordWhile); zig_unreachable(); } else { + *token_index = orig_token_index; return nullptr; } + AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, while_token); + if (name_token != nullptr) { + node->data.while_expr.name = token_buf(name_token); + } node->data.while_expr.is_inline = is_inline; ast_eat_token(pc, token_index, TokenIdLParen); @@ -1766,36 +1772,53 @@ static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index) { } /* -ForExpression(body) = option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) +ForExpression(body) = option(Symbol ":") option("inline") "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") body option("else" BlockExpression(body)) */ static AstNode *ast_parse_for_expr(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *first_token = &pc->tokens->at(*token_index); - Token *for_token; + size_t orig_token_index = *token_index; - bool is_inline; - if (first_token->id == TokenIdKeywordInline) { - is_inline = true; - for_token = &pc->tokens->at(*token_index + 1); - if (for_token->id == TokenIdKeywordFor) { - *token_index += 2; + Token *name_token = nullptr; + Token *token = &pc->tokens->at(*token_index); + + if (token->id == TokenIdSymbol) { + *token_index += 1; + Token *colon_token = &pc->tokens->at(*token_index); + if (colon_token->id == TokenIdColon) { + *token_index += 1; + name_token = token; + token = &pc->tokens->at(*token_index); } else if (mandatory) { - ast_expect_token(pc, first_token, TokenIdKeywordFor); + ast_expect_token(pc, colon_token, TokenIdColon); zig_unreachable(); } else { + *token_index = orig_token_index; return nullptr; } - } else if (first_token->id == TokenIdKeywordFor) { - for_token = first_token; - is_inline = false; + } + + bool is_inline = false; + if (token->id == TokenIdKeywordInline) { + is_inline = true; + *token_index += 1; + token = &pc->tokens->at(*token_index); + } + + Token *for_token; + if (token->id == TokenIdKeywordFor) { + for_token = token; *token_index += 1; } else if (mandatory) { - ast_expect_token(pc, first_token, TokenIdKeywordFor); + ast_expect_token(pc, token, TokenIdKeywordFor); zig_unreachable(); } else { + *token_index = orig_token_index; return nullptr; } AstNode *node = ast_create_node(pc, NodeTypeForExpr, for_token); + if (name_token != nullptr) { + node->data.for_expr.name = token_buf(name_token); + } node->data.for_expr.is_inline = is_inline; ast_eat_token(pc, token_index, TokenIdLParen); @@ -2125,32 +2148,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool /* Label: token(Symbol) token(Colon) */ -static AstNode *ast_parse_label(ParseContext *pc, size_t *token_index, bool mandatory) { - Token *symbol_token = &pc->tokens->at(*token_index); - if (symbol_token->id != TokenIdSymbol) { - if (mandatory) { - ast_expect_token(pc, symbol_token, TokenIdSymbol); - } else { - return nullptr; - } - } - - Token *colon_token = &pc->tokens->at(*token_index + 1); - if (colon_token->id != TokenIdColon) { - if (mandatory) { - ast_expect_token(pc, colon_token, TokenIdColon); - } else { - return nullptr; - } - } - - *token_index += 2; - - AstNode *node = ast_create_node(pc, NodeTypeLabel, symbol_token); - node->data.label.name = token_buf(symbol_token); - return node; -} - static bool statement_terminates_without_semicolon(AstNode *node) { switch (node->type) { case NodeTypeIfBoolExpr: @@ -2175,7 +2172,6 @@ static bool statement_terminates_without_semicolon(AstNode *node) { return node->data.defer.expr->type == NodeTypeBlock; case NodeTypeSwitchExpr: case NodeTypeBlock: - case NodeTypeLabel: return true; default: return false; @@ -2183,27 +2179,48 @@ static bool statement_terminates_without_semicolon(AstNode *node) { } /* -Block = "{" many(Statement) option(Expression) "}" +Block = option(Symbol ":") "{" many(Statement) option(Expression) "}" Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl */ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { + size_t orig_token_index = *token_index; + + Token *name_token = nullptr; Token *last_token = &pc->tokens->at(*token_index); + if (last_token->id == TokenIdSymbol) { + *token_index += 1; + Token *colon_token = &pc->tokens->at(*token_index); + if (colon_token->id == TokenIdColon) { + *token_index += 1; + name_token = last_token; + last_token = &pc->tokens->at(*token_index); + } else if (mandatory) { + ast_expect_token(pc, colon_token, TokenIdColon); + zig_unreachable(); + } else { + *token_index = orig_token_index; + return nullptr; + } + } + if (last_token->id != TokenIdLBrace) { if (mandatory) { ast_expect_token(pc, last_token, TokenIdLBrace); } else { + *token_index = orig_token_index; return nullptr; } } *token_index += 1; AstNode *node = ast_create_node(pc, NodeTypeBlock, last_token); + if (name_token != nullptr) { + node->data.block.name = token_buf(name_token); + } for (;;) { - AstNode *statement_node = ast_parse_label(pc, token_index, false); - if (!statement_node) - statement_node = ast_parse_local_var_decl(pc, token_index); + AstNode *statement_node = ast_parse_local_var_decl(pc, token_index); if (!statement_node) statement_node = ast_parse_defer_expr(pc, token_index); if (!statement_node) @@ -2225,9 +2242,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand } } - node->data.block.last_statement_is_result_expression = statement_node && !( - statement_node->type == NodeTypeLabel || - statement_node->type == NodeTypeDefer); + node->data.block.last_statement_is_result_expression = statement_node && statement_node->type != NodeTypeDefer; last_token = &pc->tokens->at(*token_index); if (last_token->id == TokenIdRBrace) { @@ -2860,12 +2875,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.switch_range.start, visit, context); visit_field(&node->data.switch_range.end, visit, context); break; - case NodeTypeLabel: - // none - break; - case NodeTypeGoto: - // none - break; case NodeTypeCompTime: visit_field(&node->data.comptime_expr.expr, visit, context); break; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index eba594e085..bb319ccb54 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -104,10 +104,8 @@ static TransScopeRoot *trans_scope_root_create(Context *c); static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); -static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope); static TransScopeBlock *trans_scope_block_find(TransScope *scope); -static TransScopeSwitch *trans_scope_switch_find(TransScope *scope); static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); @@ -265,18 +263,6 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol return node; } -static AstNode *trans_create_node_goto(Context *c, Buf *label_name) { - AstNode *goto_node = trans_create_node(c, NodeTypeGoto); - goto_node->data.goto_expr.name = label_name; - return goto_node; -} - -static AstNode *trans_create_node_label(Context *c, Buf *label_name) { - AstNode *label_node = trans_create_node(c, NodeTypeLabel); - label_node->data.label.name = label_name; - return label_node; -} - static AstNode *trans_create_node_bool(Context *c, bool value) { AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral); bool_node->data.bool_literal.value = value; @@ -2379,145 +2365,6 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt return while_scope->node; } -static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) { - TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope); - - TransScopeSwitch *switch_scope; - - const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt(); - if (var_decl_stmt == nullptr) { - switch_scope = trans_scope_switch_create(c, &block_scope->base); - } else { - AstNode *vars_node; - TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node); - if (var_scope == nullptr) - return nullptr; - if (vars_node != nullptr) - block_scope->node->data.block.statements.append(vars_node); - switch_scope = trans_scope_switch_create(c, var_scope); - } - block_scope->node->data.block.statements.append(switch_scope->switch_node); - - // TODO avoid name collisions - Buf *end_label_name = buf_create_from_str("end"); - switch_scope->end_label_name = end_label_name; - - const Expr *cond_expr = stmt->getCond(); - assert(cond_expr != nullptr); - - AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); - if (expr_node == nullptr) - return nullptr; - switch_scope->switch_node->data.switch_expr.expr = expr_node; - - AstNode *body_node; - const Stmt *body_stmt = stmt->getBody(); - if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) { - if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt, - block_scope->node, nullptr)) - { - return nullptr; - } - } else { - TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node); - if (body_scope == nullptr) - return nullptr; - if (body_node != nullptr) - block_scope->node->data.block.statements.append(body_node); - } - - if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) { - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - prong_node->data.switch_prong.expr = trans_create_node_goto(c, end_label_name); - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - } - - // This is necessary if the last switch case "falls through" the end of the switch block - block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name)); - - block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name)); - - return block_scope->node; -} - -static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node, - TransScope **out_scope) -{ - *out_node = nullptr; - - if (stmt->getRHS() != nullptr) { - emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension"); - return ErrorUnexpected; - } - - TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); - assert(switch_scope != nullptr); - - Buf *label_name = buf_sprintf("case_%" PRIu32, switch_scope->case_index); - switch_scope->case_index += 1; - - { - // Add the prong - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue); - if (item_node == nullptr) - return ErrorUnexpected; - prong_node->data.switch_prong.items.append(item_node); - - prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); - - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - } - - TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); - scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); - - AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); - if (new_scope == nullptr) - return ErrorUnexpected; - if (sub_stmt_node != nullptr) - scope_block->node->data.block.statements.append(sub_stmt_node); - - *out_scope = new_scope; - return ErrorNone; -} - -static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node, - TransScope **out_scope) -{ - *out_node = nullptr; - - TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); - assert(switch_scope != nullptr); - - Buf *label_name = buf_sprintf("default"); - - { - // Add the prong - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - - prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); - - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - switch_scope->found_default = true; - } - - TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); - scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); - - - AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); - if (new_scope == nullptr) - return ErrorUnexpected; - if (sub_stmt_node != nullptr) - scope_block->node->data.block.statements.append(sub_stmt_node); - - *out_scope = new_scope; - return ErrorNone; -} - static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) { AstNode *loop_block_node; TransScopeWhile *while_scope; @@ -2595,8 +2442,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt if (cur_scope->id == TransScopeIdWhile) { return trans_create_node(c, NodeTypeBreak); } else if (cur_scope->id == TransScopeIdSwitch) { - TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope; - return trans_create_node_goto(c, switch_scope->end_label_name); + zig_panic("TODO"); } cur_scope = cur_scope->parent; } @@ -2696,12 +2542,14 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, return wrap_stmt(out_node, out_child_scope, scope, trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); case Stmt::SwitchStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_switch_stmt(c, scope, (const SwitchStmt *)stmt)); + emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass"); + return ErrorUnexpected; case Stmt::CaseStmtClass: - return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope); + emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); + return ErrorUnexpected; case Stmt::DefaultStmtClass: - return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope); + emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass"); + return ErrorUnexpected; case Stmt::NoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); return ErrorUnexpected; @@ -3871,14 +3719,6 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop return result; } -static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) { - TransScopeSwitch *result = allocate(1); - result->base.id = TransScopeIdSwitch; - result->base.parent = parent_scope; - result->switch_node = trans_create_node(c, NodeTypeSwitchExpr); - return result; -} - static TransScopeBlock *trans_scope_block_find(TransScope *scope) { while (scope != nullptr) { if (scope->id == TransScopeIdBlock) { @@ -3889,16 +3729,6 @@ static TransScopeBlock *trans_scope_block_find(TransScope *scope) { return nullptr; } -static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) { - while (scope != nullptr) { - if (scope->id == TransScopeIdSwitch) { - return (TransScopeSwitch *)scope; - } - scope = scope->parent; - } - return nullptr; -} - static void render_aliases(Context *c) { for (size_t i = 0; i < c->aliases.length; i += 1) { Alias *alias = &c->aliases.at(i); diff --git a/std/elf.zig b/std/elf.zig index 2c5b10b3f2..60b0119894 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -243,7 +243,7 @@ pub const Elf = struct { var file_stream = io.FileInStream.init(elf.in_file); const in = &file_stream.stream; - for (elf.section_headers) |*elf_section| { + section_loop: for (elf.section_headers) |*elf_section| { if (elf_section.sh_type == SHT_NULL) continue; const name_offset = elf.string_section.offset + elf_section.name; @@ -251,15 +251,13 @@ pub const Elf = struct { for (name) |expected_c| { const target_c = %return in.readByte(); - if (target_c == 0 or expected_c != target_c) goto next_section; + if (target_c == 0 or expected_c != target_c) continue :section_loop; } { const null_byte = %return in.readByte(); if (null_byte == 0) return elf_section; } - - next_section: } return null; diff --git a/std/os/index.zig b/std/os/index.zig index d26daed9fe..3eba15ef8a 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -902,40 +902,41 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) -> %void { /// this function recursively removes its entries and then tries again. // TODO non-recursive implementation pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void { -start_over: - // First, try deleting the item as a file. This way we don't follow sym links. - if (deleteFile(allocator, full_path)) { - return; - } else |err| { - if (err == error.FileNotFound) + start_over: while (true) { + // First, try deleting the item as a file. This way we don't follow sym links. + if (deleteFile(allocator, full_path)) { return; - if (err != error.IsDir) - return err; - } - { - var dir = Dir.open(allocator, full_path) %% |err| { + } else |err| { if (err == error.FileNotFound) return; - if (err == error.NotDir) - goto start_over; - return err; - }; - defer dir.close(); + if (err != error.IsDir) + return err; + } + { + var dir = Dir.open(allocator, full_path) %% |err| { + if (err == error.FileNotFound) + return; + if (err == error.NotDir) + continue :start_over; + return err; + }; + defer dir.close(); - var full_entry_buf = ArrayList(u8).init(allocator); - defer full_entry_buf.deinit(); + var full_entry_buf = ArrayList(u8).init(allocator); + defer full_entry_buf.deinit(); - while (%return dir.next()) |entry| { - %return full_entry_buf.resize(full_path.len + entry.name.len + 1); - const full_entry_path = full_entry_buf.toSlice(); - mem.copy(u8, full_entry_path, full_path); - full_entry_path[full_path.len] = '/'; - mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name); + while (%return dir.next()) |entry| { + %return full_entry_buf.resize(full_path.len + entry.name.len + 1); + const full_entry_path = full_entry_buf.toSlice(); + mem.copy(u8, full_entry_path, full_path); + full_entry_path[full_path.len] = '/'; + mem.copy(u8, full_entry_path[full_path.len + 1..], entry.name); - %return deleteTree(allocator, full_entry_path); + %return deleteTree(allocator, full_entry_path); + } } + return deleteDir(allocator, full_path); } - return deleteDir(allocator, full_path); } pub const Dir = struct { @@ -988,58 +989,59 @@ pub const Dir = struct { /// Memory such as file names referenced in this returned entry becomes invalid /// with subsequent calls to next, as well as when this ::Dir is deinitialized. pub fn next(self: &Dir) -> %?Entry { - start_over: - if (self.index >= self.end_index) { - if (self.buf.len == 0) { - self.buf = %return self.allocator.alloc(u8, page_size); - } + start_over: while (true) { + if (self.index >= self.end_index) { + if (self.buf.len == 0) { + self.buf = %return self.allocator.alloc(u8, page_size); + } - while (true) { - const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); - const err = linux.getErrno(result); - if (err > 0) { - switch (err) { - posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, - posix.EINVAL => { - self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2); - continue; - }, - else => return unexpectedErrorPosix(err), - }; + while (true) { + const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len); + const err = linux.getErrno(result); + if (err > 0) { + switch (err) { + posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable, + posix.EINVAL => { + self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2); + continue; + }, + else => return unexpectedErrorPosix(err), + }; + } + if (result == 0) + return null; + self.index = 0; + self.end_index = result; + break; } - if (result == 0) - return null; - self.index = 0; - self.end_index = result; - break; } - } - const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); - const next_index = self.index + linux_entry.d_reclen; - self.index = next_index; + const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); + const next_index = self.index + linux_entry.d_reclen; + self.index = next_index; - const name = cstr.toSlice(&linux_entry.d_name); + const name = cstr.toSlice(&linux_entry.d_name); - // skip . and .. entries - if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { - goto start_over; - } + // skip . and .. entries + if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { + continue :start_over; + } - const type_char = self.buf[next_index - 1]; - const entry_kind = switch (type_char) { - posix.DT_BLK => Entry.Kind.BlockDevice, - posix.DT_CHR => Entry.Kind.CharacterDevice, - posix.DT_DIR => Entry.Kind.Directory, - posix.DT_FIFO => Entry.Kind.NamedPipe, - posix.DT_LNK => Entry.Kind.SymLink, - posix.DT_REG => Entry.Kind.File, - posix.DT_SOCK => Entry.Kind.UnixDomainSocket, - else => Entry.Kind.Unknown, - }; - return Entry { - .name = name, - .kind = entry_kind, - }; + const type_char = self.buf[next_index - 1]; + const entry_kind = switch (type_char) { + posix.DT_BLK => Entry.Kind.BlockDevice, + posix.DT_CHR => Entry.Kind.CharacterDevice, + posix.DT_DIR => Entry.Kind.Directory, + posix.DT_FIFO => Entry.Kind.NamedPipe, + posix.DT_LNK => Entry.Kind.SymLink, + posix.DT_REG => Entry.Kind.File, + posix.DT_SOCK => Entry.Kind.UnixDomainSocket, + else => Entry.Kind.Unknown, + }; + return Entry { + .name = name, + .kind = entry_kind, + }; + } } }; diff --git a/test/behavior.zig b/test/behavior.zig index ecb8cf74c9..96a323a6c8 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -20,7 +20,6 @@ comptime { _ = @import("cases/fn.zig"); _ = @import("cases/for.zig"); _ = @import("cases/generics.zig"); - _ = @import("cases/goto.zig"); _ = @import("cases/if.zig"); _ = @import("cases/import.zig"); _ = @import("cases/incomplete_struct_param_tld.zig"); diff --git a/test/cases/for.zig b/test/cases/for.zig index e10e7acaca..e4b8094cf5 100644 --- a/test/cases/for.zig +++ b/test/cases/for.zig @@ -55,3 +55,37 @@ test "basic for loop" { assert(mem.eql(u8, buffer[0..buf_index], expected_result)); } + +test "break from outer for loop" { + testBreakOuter(); + comptime testBreakOuter(); +} + +fn testBreakOuter() { + var array = "aoeu"; + var count: usize = 0; + outer: for (array) |_| { + for (array) |_2| { // TODO shouldn't get error for redeclaring "_" + count += 1; + break :outer; + } + } + assert(count == 1); +} + +test "continue outer for loop" { + testContinueOuter(); + comptime testContinueOuter(); +} + +fn testContinueOuter() { + var array = "aoeu"; + var counter: usize = 0; + outer: for (array) |_| { + for (array) |_2| { // TODO shouldn't get error for redeclaring "_" + counter += 1; + continue :outer; + } + } + assert(counter == array.len); +} diff --git a/test/cases/goto.zig b/test/cases/goto.zig deleted file mode 100644 index 7713bc14aa..0000000000 --- a/test/cases/goto.zig +++ /dev/null @@ -1,37 +0,0 @@ -const assert = @import("std").debug.assert; - -test "goto and labels" { - gotoLoop(); - assert(goto_counter == 10); -} -fn gotoLoop() { - var i: i32 = 0; - goto cond; -loop: - i += 1; -cond: - if (!(i < 10)) goto end; - goto_counter += 1; - goto loop; -end: -} -var goto_counter: i32 = 0; - - - -test "goto leave defer scope" { - testGotoLeaveDeferScope(true); -} -fn testGotoLeaveDeferScope(b: bool) { - var it_worked = false; - - goto entry; -exit: - if (it_worked) { - return; - } - unreachable; -entry: - defer it_worked = true; - if (b) goto exit; -} diff --git a/test/cases/while.zig b/test/cases/while.zig index 33833cecfa..c16171d4a3 100644 --- a/test/cases/while.zig +++ b/test/cases/while.zig @@ -188,6 +188,33 @@ test "while on bool with else result follow break prong" { assert(result == 10); } +test "break from outer while loop" { + testBreakOuter(); + comptime testBreakOuter(); +} + +fn testBreakOuter() { + outer: while (true) { + while (true) { + break :outer; + } + } +} + +test "continue outer while loop" { + testContinueOuter(); + comptime testContinueOuter(); +} + +fn testContinueOuter() { + var i: usize = 0; + outer: while (i < 10) : (i += 1) { + while (true) { + continue :outer; + } + } +} + fn returnNull() -> ?i32 { null } fn returnMaybe(x: i32) -> ?i32 { x } error YouWantedAnError; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fb7daea481..3446acda02 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,27 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { + cases.add("labeled break not found", + \\export fn entry() { + \\ blah: while (true) { + \\ while (true) { + \\ break :outer; + \\ } + \\ } + \\} + , ".tmp_source.zig:4:13: error: labeled loop not found: 'outer'"); + + cases.add("labeled continue not found", + \\export fn entry() { + \\ var i: usize = 0; + \\ blah: while (i < 10) : (i += 1) { + \\ while (true) { + \\ continue :outer; + \\ } + \\ } + \\} + , ".tmp_source.zig:5:13: error: labeled loop not found: 'outer'"); + cases.add("attempt to use 0 bit type in extern fn", \\extern fn foo(ptr: extern fn(&void)); \\ @@ -833,26 +854,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); - cases.add("goto jumping into block", - \\export fn f() { - \\ { - \\a_label: - \\ } - \\ goto a_label; - \\} - , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); - - cases.add("goto jumping past a defer", - \\fn f(b: bool) { - \\ if (b) goto label; - \\ defer derp(); - \\label: - \\} - \\fn derp(){} - \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } - , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); - cases.add("assign null to non-nullable pointer", \\const a: &u8 = null; \\ @@ -1854,16 +1855,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); - cases.add("cannot goto out of defer expression", - \\export fn foo() { - \\ defer { - \\ goto label; - \\ }; - \\label: - \\} - , - ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); - cases.add("calling a var args function only known at runtime", \\var foos = []fn(...) { foo1, foo2 }; \\ diff --git a/test/translate_c.zig b/test/translate_c.zig index aff2140f8d..4f545139e7 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1005,48 +1005,6 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} ); - cases.add("switch statement", - \\int foo(int x) { - \\ switch (x) { - \\ case 1: - \\ x += 1; - \\ case 2: - \\ break; - \\ case 3: - \\ case 4: - \\ return x + 1; - \\ default: - \\ return 10; - \\ } - \\ return x + 13; - \\} - , - \\fn foo(_arg_x: c_int) -> c_int { - \\ var x = _arg_x; - \\ { - \\ switch (x) { - \\ 1 => goto case_0, - \\ 2 => goto case_1, - \\ 3 => goto case_2, - \\ 4 => goto case_3, - \\ else => goto default, - \\ }; - \\ case_0: - \\ x += 1; - \\ case_1: - \\ goto end; - \\ case_2: - \\ case_3: - \\ return x + 1; - \\ default: - \\ return 10; - \\ goto end; - \\ end: - \\ }; - \\ return x + 13; - \\} - ); - cases.add("macros with field targets", \\typedef unsigned int GLbitfield; \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); @@ -1085,44 +1043,6 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub const OpenGLProcs = union_OpenGLProcs; ); - cases.add("switch statement with no default", - \\int foo(int x) { - \\ switch (x) { - \\ case 1: - \\ x += 1; - \\ case 2: - \\ break; - \\ case 3: - \\ case 4: - \\ return x + 1; - \\ } - \\ return x + 13; - \\} - , - \\fn foo(_arg_x: c_int) -> c_int { - \\ var x = _arg_x; - \\ { - \\ switch (x) { - \\ 1 => goto case_0, - \\ 2 => goto case_1, - \\ 3 => goto case_2, - \\ 4 => goto case_3, - \\ else => goto end, - \\ }; - \\ case_0: - \\ x += 1; - \\ case_1: - \\ goto end; - \\ case_2: - \\ case_3: - \\ return x + 1; - \\ goto end; - \\ end: - \\ }; - \\ return x + 13; - \\} - ); - cases.add("variable name shadowing", \\int foo(void) { \\ int x = 1; -- cgit v1.2.3 From d917815d8111b98dc237cbe2c723fa63018e02b1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 22 Dec 2017 00:50:30 -0500 Subject: explicitly return from blocks instead of last statement being expression value closes #629 --- doc/docgen.zig | 2 +- doc/langref.html.in | 5 +- example/shared_library/mathtest.zig | 2 +- src-self-hosted/parser.zig | 24 +- src/all_types.hpp | 16 +- src/analyze.cpp | 2 +- src/ast_render.cpp | 5 +- src/ir.cpp | 96 +++++--- src/parser.cpp | 53 ++--- src/translate_c.cpp | 86 ++++--- std/array_list.zig | 8 +- std/buffer.zig | 6 +- std/build.zig | 56 +++-- std/cstr.zig | 2 +- std/debug.zig | 86 ++++--- std/endian.zig | 6 +- std/fmt/errol/enum3.zig | 4 +- std/fmt/index.zig | 7 +- std/hash_map.zig | 20 +- std/heap.zig | 13 +- std/io.zig | 29 ++- std/linked_list.zig | 14 +- std/math/acos.zig | 12 +- std/math/acosh.zig | 16 +- std/math/asin.zig | 18 +- std/math/asinh.zig | 8 +- std/math/atan.zig | 12 +- std/math/atan2.zig | 16 +- std/math/atanh.zig | 10 +- std/math/cbrt.zig | 8 +- std/math/ceil.zig | 16 +- std/math/copysign.zig | 8 +- std/math/cos.zig | 24 +- std/math/cosh.zig | 8 +- std/math/exp.zig | 12 +- std/math/exp2.zig | 8 +- std/math/expm1.zig | 4 +- std/math/expo2.zig | 8 +- std/math/fabs.zig | 8 +- std/math/floor.zig | 18 +- std/math/fma.zig | 20 +- std/math/frexp.zig | 12 +- std/math/hypot.zig | 8 +- std/math/ilogb.zig | 8 +- std/math/index.zig | 16 +- std/math/inf.zig | 4 +- std/math/isfinite.zig | 4 +- std/math/isinf.zig | 12 +- std/math/isnan.zig | 6 +- std/math/isnormal.zig | 4 +- std/math/ln.zig | 8 +- std/math/log.zig | 2 +- std/math/log10.zig | 8 +- std/math/log1p.zig | 8 +- std/math/log2.zig | 8 +- std/math/modf.zig | 12 +- std/math/nan.zig | 8 +- std/math/pow.zig | 4 +- std/math/round.zig | 12 +- std/math/scalbn.zig | 8 +- std/math/signbit.zig | 8 +- std/math/sin.zig | 26 +-- std/math/sinh.zig | 8 +- std/math/sqrt.zig | 10 +- std/math/tan.zig | 20 +- std/math/tanh.zig | 12 +- std/math/trunc.zig | 12 +- std/mem.zig | 8 +- std/net.zig | 22 +- std/os/child_process.zig | 70 +++--- std/os/darwin.zig | 80 ++++--- std/os/index.zig | 19 +- std/os/linux.zig | 136 ++++++------ std/os/linux_x86_64.zig | 32 +-- std/os/path.zig | 36 +-- std/os/windows/util.zig | 4 +- std/rand.zig | 28 +-- std/sort.zig | 8 +- std/special/build_runner.zig | 16 +- std/special/builtin.zig | 18 +- std/special/compiler_rt/comparetf2.zig | 40 ++-- test/cases/align.zig | 18 +- test/cases/array.zig | 4 +- test/cases/bitcast.zig | 4 +- test/cases/bool.zig | 2 +- test/cases/cast.zig | 14 +- test/cases/defer.zig | 12 +- test/cases/enum.zig | 2 +- test/cases/enum_with_members.zig | 6 +- test/cases/error.zig | 14 +- test/cases/eval.zig | 26 +-- test/cases/fn.zig | 20 +- test/cases/for.zig | 2 +- test/cases/generics.zig | 38 ++-- test/cases/if.zig | 6 +- test/cases/import/a_namespace.zig | 2 +- test/cases/ir_block_deps.zig | 4 +- test/cases/math.zig | 22 +- test/cases/misc.zig | 30 +-- test/cases/reflection.zig | 2 +- test/cases/struct.zig | 18 +- test/cases/switch.zig | 18 +- test/cases/switch_prong_err_enum.zig | 2 +- test/cases/switch_prong_implicit_cast.zig | 4 +- test/cases/this.zig | 12 +- test/cases/try.zig | 18 +- test/cases/var_args.zig | 4 +- test/cases/while.zig | 48 ++-- test/compare_output.zig | 34 +-- test/compile_errors.zig | 357 +++++++++++++++--------------- test/debug_safety.zig | 30 +-- test/standalone/pkg_import/pkg.zig | 2 +- test/tests.zig | 6 +- test/translate_c.zig | 110 ++++----- 114 files changed, 1202 insertions(+), 1230 deletions(-) (limited to 'src/ast_render.cpp') diff --git a/doc/docgen.zig b/doc/docgen.zig index bec12d98b7..d481baf4b3 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -49,7 +49,7 @@ fn gen(in: &io.InStream, out: &io.OutStream) { if (err == error.EndOfStream) { return; } - std.debug.panic("{}", err) + std.debug.panic("{}", err); }; switch (state) { State.Start => switch (byte) { diff --git a/doc/langref.html.in b/doc/langref.html.in index faba4f8b10..162c8b3e03 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -3021,14 +3021,13 @@ const assert = @import("std").debug.assert;

    const assert = @import("std").debug.assert;
     
     // Functions are declared like this
    -// The last expression in the function can be used as the return value.
     fn add(a: i8, b: i8) -> i8 {
         if (a == 0) {
             // You can still return manually if needed.
             return b;
         }
     
    -    a + b
    +    return a + b;
     }
     
     // The export specifier makes a function externally visible in the generated
    @@ -5847,7 +5846,7 @@ ParamDeclList = "(" list(ParamDecl, ",") ")"
     
     ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
     
    -Block = option(Symbol ":") "{" many(Statement) option(Expression) "}"
    +Block = option(Symbol ":") "{" many(Statement) "}"
     
     Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
     
    diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig
    index a11642554f..bb0175bff2 100644
    --- a/example/shared_library/mathtest.zig
    +++ b/example/shared_library/mathtest.zig
    @@ -1,3 +1,3 @@
     export fn add(a: i32, b: i32) -> i32 {
    -    a + b
    +    return a + b;
     }
    diff --git a/src-self-hosted/parser.zig b/src-self-hosted/parser.zig
    index b34603f131..c997536ce2 100644
    --- a/src-self-hosted/parser.zig
    +++ b/src-self-hosted/parser.zig
    @@ -111,11 +111,11 @@ pub const Parser = struct {
         }
     
         pub fn parse(self: &Parser) -> %&ast.NodeRoot {
    -        const result = self.parseInner() %% |err| {
    +        const result = self.parseInner() %% |err| x: {
                 if (self.cleanup_root_node) |root_node| {
                     self.freeAst(root_node);
                 }
    -            err
    +            break :x err;
             };
             self.cleanup_root_node = null;
             return result;
    @@ -125,12 +125,12 @@ pub const Parser = struct {
             var stack = self.initUtilityArrayList(State);
             defer self.deinitUtilityArrayList(stack);
     
    -        const root_node = {
    +        const root_node = x: {
                 const root_node = %return self.createRoot();
                 %defer self.allocator.destroy(root_node);
                 // This stack append has to succeed for freeAst to work
                 %return stack.append(State.TopLevel);
    -            root_node
    +            break :x root_node;
             };
             assert(self.cleanup_root_node == null);
             self.cleanup_root_node = root_node;
    @@ -462,7 +462,7 @@ pub const Parser = struct {
                         } else if (token.id == Token.Id.Keyword_noalias) {
                             param_decl.noalias_token = token;
                             token = self.getNextToken();
    -                    };
    +                    }
                         if (token.id == Token.Id.Identifier) {
                             const next_token = self.getNextToken();
                             if (next_token.id == Token.Id.Colon) {
    @@ -793,14 +793,14 @@ pub const Parser = struct {
         }
     
         fn getNextToken(self: &Parser) -> Token {
    -        return if (self.put_back_count != 0) {
    +        if (self.put_back_count != 0) {
                 const put_back_index = self.put_back_count - 1;
                 const put_back_token = self.put_back_tokens[put_back_index];
                 self.put_back_count = put_back_index;
    -            put_back_token
    +            return put_back_token;
             } else {
    -            self.tokenizer.next()
    -        };
    +            return self.tokenizer.next();
    +        }
         }
     
         const RenderAstFrame = struct {
    @@ -873,7 +873,7 @@ pub const Parser = struct {
                                         Token.Id.Keyword_pub => %return stream.print("pub "),
                                         Token.Id.Keyword_export => %return stream.print("export "),
                                         else => unreachable,
    -                                };
    +                                }
                                 }
                                 if (fn_proto.extern_token) |extern_token| {
                                     %return stream.print("{} ", self.tokenizer.getTokenSlice(extern_token));
    @@ -1102,7 +1102,7 @@ fn testParse(source: []const u8, allocator: &mem.Allocator) -> %[]u8 {
     // TODO test for memory leaks
     // TODO test for valid frees
     fn testCanonical(source: []const u8) {
    -    const needed_alloc_count = {
    +    const needed_alloc_count = x: {
             // Try it once with unlimited memory, make sure it works
             var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
             var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, @maxValue(usize));
    @@ -1116,7 +1116,7 @@ fn testCanonical(source: []const u8) {
                 @panic("test failed");
             }
             failing_allocator.allocator.free(result_source);
    -        failing_allocator.index
    +        break :x failing_allocator.index;
         };
     
         // TODO make this pass
    diff --git a/src/all_types.hpp b/src/all_types.hpp
    index 87541bb918..a582f561cc 100644
    --- a/src/all_types.hpp
    +++ b/src/all_types.hpp
    @@ -26,7 +26,6 @@ struct ScopeFnDef;
     struct TypeTableEntry;
     struct VariableTableEntry;
     struct ErrorTableEntry;
    -struct LabelTableEntry;
     struct BuiltinFnEntry;
     struct TypeStructField;
     struct CodeGen;
    @@ -54,7 +53,6 @@ struct IrExecutable {
         size_t *backward_branch_count;
         size_t backward_branch_quota;
         bool invalid;
    -    ZigList all_labels;
         ZigList goto_list;
         bool is_inline;
         FnTableEntry *fn_entry;
    @@ -452,7 +450,6 @@ struct AstNodeParamDecl {
     struct AstNodeBlock {
         Buf *name;
         ZigList statements;
    -    bool last_statement_is_result_expression;
     };
     
     enum ReturnKind {
    @@ -1644,12 +1641,6 @@ struct ErrorTableEntry {
         ConstExprValue *cached_error_name_val;
     };
     
    -struct LabelTableEntry {
    -    AstNode *decl_node;
    -    IrBasicBlock *bb;
    -    bool used;
    -};
    -
     enum ScopeId {
         ScopeIdDecls,
         ScopeIdBlock,
    @@ -1693,7 +1684,12 @@ struct ScopeDecls {
     struct ScopeBlock {
         Scope base;
     
    -    HashMap label_table;
    +    Buf *name;
    +    IrBasicBlock *end_block;
    +    IrInstruction *is_comptime;
    +    ZigList *incoming_values;
    +    ZigList *incoming_blocks;
    +
         bool safety_off;
         AstNode *safety_set_node;
         bool fast_math_off;
    diff --git a/src/analyze.cpp b/src/analyze.cpp
    index 23301cc4de..9ec4db824c 100644
    --- a/src/analyze.cpp
    +++ b/src/analyze.cpp
    @@ -110,7 +110,7 @@ ScopeBlock *create_block_scope(AstNode *node, Scope *parent) {
         assert(node->type == NodeTypeBlock);
         ScopeBlock *scope = allocate(1);
         init_scope(&scope->base, ScopeIdBlock, node, parent);
    -    scope->label_table.init(1);
    +    scope->name = node->data.block.name;
         return scope;
     }
     
    diff --git a/src/ast_render.cpp b/src/ast_render.cpp
    index e64a19d42d..f0912285f0 100644
    --- a/src/ast_render.cpp
    +++ b/src/ast_render.cpp
    @@ -478,10 +478,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
                     AstNode *statement = node->data.block.statements.at(i);
                     print_indent(ar);
                     render_node_grouped(ar, statement);
    -                if (!(i == node->data.block.statements.length - 1 &&
    -                      node->data.block.last_statement_is_result_expression)) {
    -                    fprintf(ar->f, ";");
    -                }
    +                fprintf(ar->f, ";");
                     fprintf(ar->f, "\n");
                 }
                 ar->indent -= ar->indent_size;
    diff --git a/src/ir.cpp b/src/ir.cpp
    index d3dd58aaff..a0f5a9be47 100644
    --- a/src/ir.cpp
    +++ b/src/ir.cpp
    @@ -3514,7 +3514,11 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
     static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
         assert(block_node->type == NodeTypeBlock);
     
    +    ZigList incoming_values = {0};
    +    ZigList incoming_blocks = {0};
    +
         ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
    +
         Scope *outer_block_scope = &scope_block->base;
         Scope *child_scope = outer_block_scope;
     
    @@ -3528,9 +3532,15 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
             return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
         }
     
    +    if (block_node->data.block.name != nullptr) {
    +        scope_block->incoming_blocks = &incoming_blocks;
    +        scope_block->incoming_values = &incoming_values;
    +        scope_block->end_block = ir_build_basic_block(irb, parent_scope, "BlockEnd");
    +        scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
    +    }
    +
         bool is_continuation_unreachable = false;
         IrInstruction *noreturn_return_value = nullptr;
    -    IrInstruction *return_value = nullptr;
         for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
             AstNode *statement_node = block_node->data.block.statements.at(i);
     
    @@ -3548,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
                 // variable declarations start a new scope
                 IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
                 child_scope = decl_var_instruction->var->child_scope;
    -        } else {
    -            // label, defer, variable declaration will never be the result expression
    -            if (block_node->data.block.last_statement_is_result_expression &&
    -                i == block_node->data.block.statements.length - 1) {
    -                // this is the result value statement
    -                return_value = statement_value;
    -            } else {
    -                // there are more statements ahead of this one. this statement's value must be void
    -                if (statement_value != irb->codegen->invalid_instruction) {
    -                    ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
    -                }
    -            }
    +        } else if (statement_value != irb->codegen->invalid_instruction) {
    +            // this statement's value must be void
    +            ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
             }
         }
     
         if (is_continuation_unreachable) {
             assert(noreturn_return_value != nullptr);
    -        return noreturn_return_value;
    +        if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) {
    +            return noreturn_return_value;
    +        }
    +    } else {
    +        incoming_blocks.append(irb->current_basic_block);
    +        incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
         }
    -    // control flow falls out of block
     
    -    if (block_node->data.block.last_statement_is_result_expression) {
    -        // return value was determined by the last statement
    -        assert(return_value != nullptr);
    +    if (block_node->data.block.name != nullptr) {
    +        ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
    +        ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
    +        ir_set_cursor_at_end(irb, scope_block->end_block);
    +        return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
         } else {
    -        // return value is implicitly void
    -        assert(return_value == nullptr);
    -        return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
    +        ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
    +        return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
         }
    -
    -    ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
    -
    -    return return_value;
     }
     
     static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
    @@ -5952,6 +5954,31 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo
         return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
     }
     
    +static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
    +    IrInstruction *is_comptime;
    +    if (ir_should_inline(irb->exec, break_scope)) {
    +        is_comptime = ir_build_const_bool(irb, break_scope, node, true);
    +    } else {
    +        is_comptime = block_scope->is_comptime;
    +    }
    +
    +    IrInstruction *result_value;
    +    if (node->data.break_expr.expr) {
    +        result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
    +        if (result_value == irb->codegen->invalid_instruction)
    +            return irb->codegen->invalid_instruction;
    +    } else {
    +        result_value = ir_build_const_void(irb, break_scope, node);
    +    }
    +
    +    IrBasicBlock *dest_block = block_scope->end_block;
    +    ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false);
    +
    +    block_scope->incoming_blocks->append(irb->current_basic_block);
    +    block_scope->incoming_values->append(result_value);
    +    return ir_build_br(irb, break_scope, node, dest_block, is_comptime);
    +}
    +
     static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
         assert(node->type == NodeTypeBreak);
     
    @@ -5959,14 +5986,14 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
         // * function definition scope or global scope => error, break outside loop
         // * defer expression scope => error, cannot break out of defer expression
         // * loop scope => OK
    +    // * (if it's a labeled break) labeled block => OK
     
         Scope *search_scope = break_scope;
         ScopeLoop *loop_scope;
    -    bool saw_any_loop_scope = false;
         for (;;) {
             if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
    -            if (saw_any_loop_scope) {
    -                add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.break_expr.name)));
    +            if (node->data.break_expr.name != nullptr) {
    +                add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name)));
                     return irb->codegen->invalid_instruction;
                 } else {
                     add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop"));
    @@ -5977,13 +6004,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
                 return irb->codegen->invalid_instruction;
             } else if (search_scope->id == ScopeIdLoop) {
                 ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
    -            saw_any_loop_scope = true;
                 if (node->data.break_expr.name == nullptr ||
                     (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name)))
                 {
                     loop_scope = this_loop_scope;
                     break;
                 }
    +        } else if (search_scope->id == ScopeIdBlock) {
    +            ScopeBlock *this_block_scope = (ScopeBlock *)search_scope;
    +            if (node->data.break_expr.name != nullptr &&
    +                (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name)))
    +            {
    +                assert(this_block_scope->end_block != nullptr);
    +                return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
    +            }
             }
             search_scope = search_scope->parent;
         }
    @@ -6022,10 +6056,9 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
     
         Scope *search_scope = continue_scope;
         ScopeLoop *loop_scope;
    -    bool saw_any_loop_scope = false;
         for (;;) {
             if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
    -            if (saw_any_loop_scope) {
    +            if (node->data.continue_expr.name != nullptr) {
                     add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name)));
                     return irb->codegen->invalid_instruction;
                 } else {
    @@ -6037,7 +6070,6 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
                 return irb->codegen->invalid_instruction;
             } else if (search_scope->id == ScopeIdLoop) {
                 ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
    -            saw_any_loop_scope = true;
                 if (node->data.continue_expr.name == nullptr ||
                     (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name)))
                 {
    diff --git a/src/parser.cpp b/src/parser.cpp
    index b5fdd681e8..d069a23c5f 100644
    --- a/src/parser.cpp
    +++ b/src/parser.cpp
    @@ -748,7 +748,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
             node->data.fn_call_expr.is_builtin = true;
     
             return node;
    -    } else if (token->id == TokenIdSymbol) {
    +    }
    +
    +    AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false);
    +    if (block_expr_node) {
    +        return block_expr_node;
    +    }
    +
    +    if (token->id == TokenIdSymbol) {
             *token_index += 1;
             AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
             node->data.symbol_expr.symbol = token_buf(token);
    @@ -760,11 +767,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
             return grouped_expr_node;
         }
     
    -    AstNode *block_expr_node = ast_parse_block_expr(pc, token_index, false);
    -    if (block_expr_node) {
    -        return block_expr_node;
    -    }
    -
         AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false);
         if (array_type_node) {
             return array_type_node;
    @@ -2145,9 +2147,6 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
         return nullptr;
     }
     
    -/*
    -Label: token(Symbol) token(Colon)
    -*/
     static bool statement_terminates_without_semicolon(AstNode *node) {
         switch (node->type) {
             case NodeTypeIfBoolExpr:
    @@ -2179,7 +2178,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
     }
     
     /*
    -Block = option(Symbol ":") "{" many(Statement) option(Expression) "}"
    +Block = option(Symbol ":") "{" many(Statement) "}"
     Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl
     */
     static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) {
    @@ -2220,6 +2219,12 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
         }
     
         for (;;) {
    +        last_token = &pc->tokens->at(*token_index);
    +        if (last_token->id == TokenIdRBrace) {
    +            *token_index += 1;
    +            return node;
    +        }
    +
             AstNode *statement_node = ast_parse_local_var_decl(pc, token_index);
             if (!statement_node)
                 statement_node = ast_parse_defer_expr(pc, token_index);
    @@ -2228,32 +2233,14 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
             if (!statement_node)
                 statement_node = ast_parse_expression(pc, token_index, false);
     
    -        bool semicolon_expected = true;
    -        if (statement_node) {
    -            node->data.block.statements.append(statement_node);
    -            if (statement_terminates_without_semicolon(statement_node)) {
    -                semicolon_expected = false;
    -            } else {
    -                if (statement_node->type == NodeTypeDefer) {
    -                    // defer without a block body requires a semicolon
    -                    Token *token = &pc->tokens->at(*token_index);
    -                    ast_expect_token(pc, token, TokenIdSemicolon);
    -                }
    -            }
    +        if (!statement_node) {
    +            ast_invalid_token_error(pc, last_token);
             }
     
    -        node->data.block.last_statement_is_result_expression = statement_node && statement_node->type != NodeTypeDefer;
    +        node->data.block.statements.append(statement_node);
     
    -        last_token = &pc->tokens->at(*token_index);
    -        if (last_token->id == TokenIdRBrace) {
    -            *token_index += 1;
    -            return node;
    -        } else if (!semicolon_expected) {
    -            continue;
    -        } else if (last_token->id == TokenIdSemicolon) {
    -            *token_index += 1;
    -        } else {
    -            ast_invalid_token_error(pc, last_token);
    +        if (!statement_terminates_without_semicolon(statement_node)) {
    +            ast_eat_token(pc, token_index, TokenIdSemicolon);
             }
         }
         zig_unreachable();
    diff --git a/src/translate_c.cpp b/src/translate_c.cpp
    index bb319ccb54..2d0772aeaa 100644
    --- a/src/translate_c.cpp
    +++ b/src/translate_c.cpp
    @@ -171,6 +171,20 @@ static AstNode * trans_create_node(Context *c, NodeType id) {
         return node;
     }
     
    +static AstNode *trans_create_node_break(Context *c, Buf *label_name, AstNode *value_node) {
    +    AstNode *node = trans_create_node(c, NodeTypeBreak);
    +    node->data.break_expr.name = label_name;
    +    node->data.break_expr.expr = value_node;
    +    return node;
    +}
    +
    +static AstNode *trans_create_node_return(Context *c, AstNode *value_node) {
    +    AstNode *node = trans_create_node(c, NodeTypeReturnExpr);
    +    node->data.return_expr.kind = ReturnKindUnconditional;
    +    node->data.return_expr.expr = value_node;
    +    return node;
    +}
    +
     static AstNode *trans_create_node_if(Context *c, AstNode *cond_node, AstNode *then_node, AstNode *else_node) {
         AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr);
         node->data.if_bool_expr.condition = cond_node;
    @@ -372,8 +386,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r
     
         AstNode *block = trans_create_node(c, NodeTypeBlock);
         block->data.block.statements.resize(1);
    -    block->data.block.statements.items[0] = fn_call_node;
    -    block->data.block.last_statement_is_result_expression = true;
    +    block->data.block.statements.items[0] = trans_create_node_return(c, fn_call_node);
     
         fn_def->data.fn_def.body = block;
         return fn_def;
    @@ -1140,13 +1153,15 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
         } else {
             // worst case
             // c: lhs = rhs
    -        // zig: {
    +        // zig: x: {
             // zig:     const _tmp = rhs;
             // zig:     lhs = _tmp;
    -        // zig:     _tmp
    +        // zig:     break :x _tmp
             // zig: }
     
             TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
    +        Buf *label_name = buf_create_from_str("x");
    +        child_scope->node->data.block.name = label_name;
     
             // const _tmp = rhs;
             AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue);
    @@ -1163,9 +1178,9 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
                 trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign,
                     trans_create_node_symbol(c, tmp_var_name)));
     
    -        // _tmp
    -        child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
    -        child_scope->node->data.block.last_statement_is_result_expression = true;
    +        // break :x _tmp
    +        AstNode *tmp_symbol_node = trans_create_node_symbol(c, tmp_var_name);
    +        child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, tmp_symbol_node));
     
             return child_scope->node;
         }
    @@ -1270,6 +1285,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
             case BO_Comma:
                 {
                     TransScopeBlock *scope_block = trans_scope_block_create(c, scope);
    +                Buf *label_name = buf_create_from_str("x");
    +                scope_block->node->data.block.name = label_name;
    +
                     AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue);
                     if (lhs == nullptr)
                         return nullptr;
    @@ -1278,9 +1296,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
                     AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue);
                     if (rhs == nullptr)
                         return nullptr;
    -                scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
    -
    -                scope_block->node->data.block.last_statement_is_result_expression = true;
    +                scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs)));
                     return scope_block->node;
                 }
             case BO_MulAssign:
    @@ -1320,14 +1336,16 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
         } else {
             // need more complexity. worst case, this looks like this:
             // c:   lhs >>= rhs
    -        // zig: {
    +        // zig: x: {
             // zig:     const _ref = &lhs;
             // zig:     *_ref = result_type(operation_type(*_ref) >> u5(rhs));
    -        // zig:     *_ref
    +        // zig:     break :x *_ref
             // zig: }
             // where u5 is the appropriate type
     
             TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
    +        Buf *label_name = buf_create_from_str("x");
    +        child_scope->node->data.block.name = label_name;
     
             // const _ref = &lhs;
             AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
    @@ -1369,11 +1387,11 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
             child_scope->node->data.block.statements.append(assign_statement);
     
             if (result_used == ResultUsedYes) {
    -            // *_ref
    +            // break :x *_ref
                 child_scope->node->data.block.statements.append(
    -                trans_create_node_prefix_op(c, PrefixOpDereference,
    -                    trans_create_node_symbol(c, tmp_var_name)));
    -            child_scope->node->data.block.last_statement_is_result_expression = true;
    +                trans_create_node_break(c, label_name, 
    +                    trans_create_node_prefix_op(c, PrefixOpDereference,
    +                        trans_create_node_symbol(c, tmp_var_name))));
             }
     
             return child_scope->node;
    @@ -1394,13 +1412,15 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
         } else {
             // need more complexity. worst case, this looks like this:
             // c:   lhs += rhs
    -        // zig: {
    +        // zig: x: {
             // zig:     const _ref = &lhs;
             // zig:     *_ref = *_ref + rhs;
    -        // zig:     *_ref
    +        // zig:     break :x *_ref
             // zig: }
     
             TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
    +        Buf *label_name = buf_create_from_str("x");
    +        child_scope->node->data.block.name = label_name;
     
             // const _ref = &lhs;
             AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
    @@ -1427,11 +1447,11 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
                     rhs));
             child_scope->node->data.block.statements.append(assign_statement);
     
    -        // *_ref
    +        // break :x *_ref
             child_scope->node->data.block.statements.append(
    -            trans_create_node_prefix_op(c, PrefixOpDereference,
    -                trans_create_node_symbol(c, tmp_var_name)));
    -        child_scope->node->data.block.last_statement_is_result_expression = true;
    +            trans_create_node_break(c, label_name,
    +                trans_create_node_prefix_op(c, PrefixOpDereference,
    +                    trans_create_node_symbol(c, tmp_var_name))));
     
             return child_scope->node;
         }
    @@ -1726,13 +1746,15 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
         }
         // worst case
         // c: expr++
    -    // zig: {
    +    // zig: x: {
         // zig:     const _ref = &expr;
         // zig:     const _tmp = *_ref;
         // zig:     *_ref += 1;
    -    // zig:     _tmp
    +    // zig:     break :x _tmp
         // zig: }
         TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
    +    Buf *label_name = buf_create_from_str("x");
    +    child_scope->node->data.block.name = label_name;
     
         // const _ref = &expr;
         AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
    @@ -1758,9 +1780,8 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
             trans_create_node_unsigned(c, 1));
         child_scope->node->data.block.statements.append(assign_statement);
     
    -    // _tmp
    -    child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
    -    child_scope->node->data.block.last_statement_is_result_expression = true;
    +    // break :x _tmp
    +    child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, trans_create_node_symbol(c, tmp_var_name)));
     
         return child_scope->node;
     }
    @@ -1781,12 +1802,14 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
         }
         // worst case
         // c: ++expr
    -    // zig: {
    +    // zig: x: {
         // zig:     const _ref = &expr;
         // zig:     *_ref += 1;
    -    // zig:     *_ref
    +    // zig:     break :x *_ref
         // zig: }
         TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
    +    Buf *label_name = buf_create_from_str("x");
    +    child_scope->node->data.block.name = label_name;
     
         // const _ref = &expr;
         AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
    @@ -1805,11 +1828,10 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
             trans_create_node_unsigned(c, 1));
         child_scope->node->data.block.statements.append(assign_statement);
     
    -    // *_ref
    +    // break :x *_ref
         AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
                 trans_create_node_symbol(c, ref_var_name));
    -    child_scope->node->data.block.statements.append(deref_expr);
    -    child_scope->node->data.block.last_statement_is_result_expression = true;
    +    child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr));
     
         return child_scope->node;
     }
    diff --git a/std/array_list.zig b/std/array_list.zig
    index 5d043075c3..04db4dd280 100644
    --- a/std/array_list.zig
    +++ b/std/array_list.zig
    @@ -8,7 +8,7 @@ pub fn ArrayList(comptime T: type) -> type {
     }
     
     pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
    -    struct {
    +    return struct {
             const Self = this;
     
             /// Use toSlice instead of slicing this directly, because if you don't
    @@ -20,11 +20,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
     
             /// Deinitialize with `deinit` or use `toOwnedSlice`.
             pub fn init(allocator: &Allocator) -> Self {
    -            Self {
    +            return Self {
                     .items = []align(A) T{},
                     .len = 0,
                     .allocator = allocator,
    -            }
    +            };
             }
     
             pub fn deinit(l: &Self) {
    @@ -107,7 +107,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) -> type{
                     return null;
                 return self.pop();
             }
    -    }
    +    };
     }
     
     test "basic ArrayList test" {
    diff --git a/std/buffer.zig b/std/buffer.zig
    index 73a38fff5b..267d9b6353 100644
    --- a/std/buffer.zig
    +++ b/std/buffer.zig
    @@ -30,9 +30,9 @@ pub const Buffer = struct {
         /// * ::replaceContentsBuffer
         /// * ::resize
         pub fn initNull(allocator: &Allocator) -> Buffer {
    -        Buffer {
    +        return Buffer {
                 .list = ArrayList(u8).init(allocator),
    -        }
    +        };
         }
     
         /// Must deinitialize with deinit.
    @@ -120,7 +120,7 @@ pub const Buffer = struct {
         }
     
         pub fn eql(self: &const Buffer, m: []const u8) -> bool {
    -        mem.eql(u8, self.toSliceConst(), m)
    +        return mem.eql(u8, self.toSliceConst(), m);
         }
     
         pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
    diff --git a/std/build.zig b/std/build.zig
    index c1c42a4bc1..0a23a77f80 100644
    --- a/std/build.zig
    +++ b/std/build.zig
    @@ -221,11 +221,11 @@ pub const Builder = struct {
         }
     
         pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
    -        Version {
    +        return Version {
                 .major = major,
                 .minor = minor,
                 .patch = patch,
    -        }
    +        };
         }
     
         pub fn addCIncludePath(self: &Builder, path: []const u8) {
    @@ -432,16 +432,16 @@ pub const Builder = struct {
             const release_safe = self.option(bool, "release-safe", "optimizations on and safety on") ?? false;
             const release_fast = self.option(bool, "release-fast", "optimizations on and safety off") ?? false;
     
    -        const mode = if (release_safe and !release_fast) {
    +        const mode = if (release_safe and !release_fast)
                 builtin.Mode.ReleaseSafe
    -        } else if (release_fast and !release_safe) {
    +        else if (release_fast and !release_safe)
                 builtin.Mode.ReleaseFast
    -        } else if (!release_fast and !release_safe) {
    +        else if (!release_fast and !release_safe)
                 builtin.Mode.Debug
    -        } else {
    +        else x: {
                 warn("Both -Drelease-safe and -Drelease-fast specified");
                 self.markInvalidUserInput();
    -            builtin.Mode.Debug
    +            break :x builtin.Mode.Debug;
             };
             self.release_mode = mode;
             return mode;
    @@ -506,7 +506,7 @@ pub const Builder = struct {
         }
     
         fn typeToEnum(comptime T: type) -> TypeId {
    -        switch (@typeId(T)) {
    +        return switch (@typeId(T)) {
                 builtin.TypeId.Int => TypeId.Int,
                 builtin.TypeId.Float => TypeId.Float,
                 builtin.TypeId.Bool => TypeId.Bool,
    @@ -515,7 +515,7 @@ pub const Builder = struct {
                     []const []const u8 => TypeId.List,
                     else => @compileError("Unsupported type: " ++ @typeName(T)),
                 },
    -        }
    +        };
         }
     
         fn markInvalidUserInput(self: &Builder) {
    @@ -590,8 +590,7 @@ pub const Builder = struct {
     
                     return error.UncleanExit;
                 },
    -        };
    -
    +        }
         }
     
         pub fn makePath(self: &Builder, path: []const u8) -> %void {
    @@ -662,13 +661,12 @@ pub const Builder = struct {
             if (builtin.environ == builtin.Environ.msvc) {
                 return "cl.exe";
             } else {
    -            return os.getEnvVarOwned(self.allocator, "CC") %% |err| {
    -                if (err == error.EnvironmentVariableNotFound) {
    +            return os.getEnvVarOwned(self.allocator, "CC") %% |err| 
    +                if (err == error.EnvironmentVariableNotFound)
                         ([]const u8)("cc")
    -                } else {
    -                    debug.panic("Unable to get environment variable: {}", err);
    -                }
    -            };
    +                else
    +                    debug.panic("Unable to get environment variable: {}", err)
    +            ;
             }
         }
     
    @@ -1079,11 +1077,10 @@ pub const LibExeObjStep = struct {
         }
     
         pub fn getOutputPath(self: &LibExeObjStep) -> []const u8 {
    -        if (self.output_path) |output_path| {
    +        return if (self.output_path) |output_path|
                 output_path
    -        } else {
    -            %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename)
    -        }
    +        else
    +            %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_filename);
         }
     
         pub fn setOutputHPath(self: &LibExeObjStep, file_path: []const u8) {
    @@ -1096,11 +1093,10 @@ pub const LibExeObjStep = struct {
         }
     
         pub fn getOutputHPath(self: &LibExeObjStep) -> []const u8 {
    -        if (self.output_h_path) |output_h_path| {
    +        return if (self.output_h_path) |output_h_path|
                 output_h_path
    -        } else {
    -            %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename)
    -        }
    +        else
    +            %%os.path.join(self.builder.allocator, self.builder.cache_root, self.out_h_filename);
         }
     
         pub fn addAssemblyFile(self: &LibExeObjStep, path: []const u8) {
    @@ -1618,7 +1614,7 @@ pub const TestStep = struct {
     
         pub fn init(builder: &Builder, root_src: []const u8) -> TestStep {
             const step_name = builder.fmt("test {}", root_src);
    -        TestStep {
    +        return TestStep {
                 .step = Step.init(step_name, builder.allocator, make),
                 .builder = builder,
                 .root_src = root_src,
    @@ -1629,7 +1625,7 @@ pub const TestStep = struct {
                 .link_libs = BufSet.init(builder.allocator),
                 .target = Target { .Native = {} },
                 .exec_cmd_args = null,
    -        }
    +        };
         }
     
         pub fn setVerbose(self: &TestStep, value: bool) {
    @@ -1936,16 +1932,16 @@ pub const Step = struct {
         done_flag: bool,
     
         pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
    -        Step {
    +        return Step {
                 .name = name,
                 .makeFn = makeFn,
                 .dependencies = ArrayList(&Step).init(allocator),
                 .loop_flag = false,
                 .done_flag = false,
    -        }
    +        };
         }
         pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
    -        init(name, allocator, makeNoOp)
    +        return init(name, allocator, makeNoOp);
         }
     
         pub fn make(self: &Step) -> %void {
    diff --git a/std/cstr.zig b/std/cstr.zig
    index e29f90fc01..445f7ab892 100644
    --- a/std/cstr.zig
    +++ b/std/cstr.zig
    @@ -17,7 +17,7 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 {
             return -1;
         } else {
             return 0;
    -    };
    +    }
     }
     
     pub fn toSliceConst(str: &const u8) -> []const u8 {
    diff --git a/std/debug.zig b/std/debug.zig
    index 1035948e3e..a683b5ae15 100644
    --- a/std/debug.zig
    +++ b/std/debug.zig
    @@ -32,7 +32,7 @@ fn getStderrStream() -> %&io.OutStream {
             const st = &stderr_file_out_stream.stream;
             stderr_stream = st;
             return st;
    -    };
    +    }
     }
     
     /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
    @@ -52,9 +52,9 @@ pub fn assert(ok: bool) {
             // we insert an explicit call to @panic instead of unreachable.
             // TODO we should use `assertOrPanic` in tests and remove this logic.
             if (builtin.is_test) {
    -            @panic("assertion failure")
    +            @panic("assertion failure");
             } else {
    -            unreachable // assertion failure
    +            unreachable; // assertion failure
             }
         }
     }
    @@ -175,7 +175,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
                                 return_address, compile_unit_name);
                         },
                         else => return err,
    -                };
    +                }
                 }
             },
             builtin.ObjectFormat.coff => {
    @@ -357,7 +357,7 @@ const Die = struct {
                 FormValue.String => |value| value,
                 FormValue.StrPtr => |offset| getString(st, offset),
                 else => error.InvalidDebugInfo,
    -        }
    +        };
         }
     };
     
    @@ -403,7 +403,7 @@ const LineNumberProgram = struct {
         pub fn init(is_stmt: bool, include_dirs: []const []const u8,
             file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
         {
    -        LineNumberProgram {
    +        return LineNumberProgram {
                 .address = 0,
                 .file = 1,
                 .line = 1,
    @@ -421,7 +421,7 @@ const LineNumberProgram = struct {
                 .prev_is_stmt = undefined,
                 .prev_basic_block = undefined,
                 .prev_end_sequence = undefined,
    -        }
    +        };
         }
     
         pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
    @@ -430,14 +430,11 @@ const LineNumberProgram = struct {
                     return error.MissingDebugInfo;
                 } else if (self.prev_file - 1 >= self.file_entries.len) {
                     return error.InvalidDebugInfo;
    -            } else {
    -                &self.file_entries.items[self.prev_file - 1]
    -            };
    +            } else &self.file_entries.items[self.prev_file - 1];
    +
                 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
                     return error.InvalidDebugInfo;
    -            } else {
    -                self.include_dirs[file_entry.dir_index]
    -            };
    +            } else self.include_dirs[file_entry.dir_index];
                 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
                 %defer self.file_entries.allocator.free(file_name);
                 return LineInfo {
    @@ -494,28 +491,21 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size:
     }
     
     fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
    -    FormValue { .Const = Constant {
    +    return FormValue { .Const = Constant {
             .signed = signed,
             .payload = %return readAllocBytes(allocator, in_stream, size),
    -    }}
    +    }};
     }
     
     fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
    -    return if (is_64) {
    -        %return in_stream.readIntLe(u64)
    -    } else {
    -        u64(%return in_stream.readIntLe(u32))
    -    };
    +    return if (is_64) %return in_stream.readIntLe(u64)
    +    else u64(%return in_stream.readIntLe(u32)) ;
     }
     
     fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
    -    return if (@sizeOf(usize) == 4) {
    -        u64(%return in_stream.readIntLe(u32))
    -    } else if (@sizeOf(usize) == 8) {
    -        %return in_stream.readIntLe(u64)
    -    } else {
    -        unreachable;
    -    };
    +    return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
    +    else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
    +    else unreachable;
     }
     
     fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
    @@ -534,9 +524,9 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
             DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
             DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
             DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
    -        DW.FORM_block => {
    +        DW.FORM_block => x: {
                 const block_len = %return readULeb128(in_stream);
    -            parseFormValueBlockLen(allocator, in_stream, block_len)
    +            return parseFormValueBlockLen(allocator, in_stream, block_len);
             },
             DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
             DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
    @@ -545,7 +535,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
             DW.FORM_udata, DW.FORM_sdata => {
                 const block_len = %return readULeb128(in_stream);
                 const signed = form_id == DW.FORM_sdata;
    -            parseFormValueConstant(allocator, in_stream, signed, block_len)
    +            return parseFormValueConstant(allocator, in_stream, signed, block_len);
             },
             DW.FORM_exprloc => {
                 const size = %return readULeb128(in_stream);
    @@ -562,7 +552,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
             DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
             DW.FORM_ref_udata => {
                 const ref_len = %return readULeb128(in_stream);
    -            parseFormValueRefLen(allocator, in_stream, ref_len)
    +            return parseFormValueRefLen(allocator, in_stream, ref_len);
             },
     
             DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
    @@ -572,10 +562,10 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
             DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
             DW.FORM_indirect => {
                 const child_form_id = %return readULeb128(in_stream);
    -            parseFormValue(allocator, in_stream, child_form_id, is_64)
    +            return parseFormValue(allocator, in_stream, child_form_id, is_64);
             },
             else => error.InvalidDebugInfo,
    -    }
    +    };
     }
     
     fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
    @@ -852,11 +842,9 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
             const version = %return in_stream.readInt(st.elf.endian, u16);
             if (version < 2 or version > 5) return error.InvalidDebugInfo;
     
    -        const debug_abbrev_offset = if (is_64) {
    -            %return in_stream.readInt(st.elf.endian, u64)
    -        } else {
    -            %return in_stream.readInt(st.elf.endian, u32)
    -        };
    +        const debug_abbrev_offset =
    +            if (is_64) %return in_stream.readInt(st.elf.endian, u64)
    +            else %return in_stream.readInt(st.elf.endian, u32);
     
             const address_size = %return in_stream.readByte();
             if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
    @@ -872,28 +860,28 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
             if (compile_unit_die.tag_id != DW.TAG_compile_unit)
                 return error.InvalidDebugInfo;
     
    -        const pc_range = {
    +        const pc_range = x: {
                 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
                     if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
                         const pc_end = switch (*high_pc_value) {
                             FormValue.Address => |value| value,
    -                        FormValue.Const => |value| {
    +                        FormValue.Const => |value| b: {
                                 const offset = %return value.asUnsignedLe();
    -                            low_pc + offset
    +                            break :b (low_pc + offset);
                             },
                             else => return error.InvalidDebugInfo,
                         };
    -                    PcRange {
    +                    break :x PcRange {
                             .start = low_pc,
                             .end = pc_end,
    -                    }
    +                    };
                     } else {
    -                    null
    +                    break :x null;
                     }
                 } else |err| {
                     if (err != error.MissingDebugInfo)
                         return err;
    -                null
    +                break :x null;
                 }
             };
     
    @@ -949,12 +937,12 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUn
     fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
         const first_32_bits = %return in_stream.readIntLe(u32);
         *is_64 = (first_32_bits == 0xffffffff);
    -    return if (*is_64) {
    -        %return in_stream.readIntLe(u64)
    +    if (*is_64) {
    +        return in_stream.readIntLe(u64);
         } else {
             if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
    -        u64(first_32_bits)
    -    };
    +        return u64(first_32_bits);
    +    }
     }
     
     fn readULeb128(in_stream: &io.InStream) -> %u64 {
    diff --git a/std/endian.zig b/std/endian.zig
    index 2dc6b8d34e..9f2d2c8dcd 100644
    --- a/std/endian.zig
    +++ b/std/endian.zig
    @@ -2,15 +2,15 @@ const mem = @import("mem.zig");
     const builtin = @import("builtin");
     
     pub fn swapIfLe(comptime T: type, x: T) -> T {
    -    swapIf(false, T, x)
    +    return swapIf(false, T, x);
     }
     
     pub fn swapIfBe(comptime T: type, x: T) -> T {
    -    swapIf(true, T, x)
    +    return swapIf(true, T, x);
     }
     
     pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
    -    if (builtin.endian == endian) swap(T, x) else x
    +    return if (builtin.endian == endian) swap(T, x) else x;
     }
     
     pub fn swap(comptime T: type, x: T) -> T {
    diff --git a/std/fmt/errol/enum3.zig b/std/fmt/errol/enum3.zig
    index 93861cce74..feb84da9a4 100644
    --- a/std/fmt/errol/enum3.zig
    +++ b/std/fmt/errol/enum3.zig
    @@ -439,10 +439,10 @@ const Slab = struct {
     };
     
     fn slab(str: []const u8, exp: i32) -> Slab {
    -    Slab {
    +    return Slab {
             .str = str,
             .exp = exp,
    -    }
    +    };
     }
     
     pub const enum3_data = []Slab {
    diff --git a/std/fmt/index.zig b/std/fmt/index.zig
    index 59376e0458..53fd085488 100644
    --- a/std/fmt/index.zig
    +++ b/std/fmt/index.zig
    @@ -251,11 +251,10 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
         %return output(context, float_decimal.digits[0..1]);
         %return output(context, ".");
         if (float_decimal.digits.len > 1) {
    -        const num_digits = if (@typeOf(value) == f32) {
    +        const num_digits = if (@typeOf(value) == f32)
                 math.min(usize(9), float_decimal.digits.len)
    -        } else {
    -            float_decimal.digits.len
    -        };
    +        else
    +            float_decimal.digits.len;
             %return output(context, float_decimal.digits[1 .. num_digits]);
         } else {
             %return output(context, "0");
    diff --git a/std/hash_map.zig b/std/hash_map.zig
    index d124d7b573..837ee07423 100644
    --- a/std/hash_map.zig
    +++ b/std/hash_map.zig
    @@ -12,7 +12,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
         comptime hash: fn(key: K)->u32,
         comptime eql: fn(a: K, b: K)->bool) -> type
     {
    -    struct {
    +    return struct {
             entries: []Entry,
             size: usize,
             max_distance_from_start_index: usize,
    @@ -51,19 +51,19 @@ pub fn HashMap(comptime K: type, comptime V: type,
                             return entry;
                         }
                     }
    -                unreachable // no next item
    +                unreachable; // no next item
                 }
             };
     
             pub fn init(allocator: &Allocator) -> Self {
    -            Self {
    +            return Self {
                     .entries = []Entry{},
                     .allocator = allocator,
                     .size = 0,
                     .max_distance_from_start_index = 0,
                     // it doesn't actually matter what we set this to since we use wrapping integer arithmetic
                     .modification_count = undefined,
    -            }
    +            };
             }
     
             pub fn deinit(hm: &Self) {
    @@ -133,7 +133,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
                         entry.distance_from_start_index -= 1;
                         entry = next_entry;
                     }
    -                unreachable // shifting everything in the table
    +                unreachable; // shifting everything in the table
                 }}
                 return null;
             }
    @@ -169,7 +169,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
                 const start_index = hm.keyToIndex(key);
                 var roll_over: usize = 0;
                 var distance_from_start_index: usize = 0;
    -            while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1}) {
    +            while (roll_over < hm.entries.len) : ({roll_over += 1; distance_from_start_index += 1;}) {
                     const index = (start_index + roll_over) % hm.entries.len;
                     const entry = &hm.entries[index];
     
    @@ -210,7 +210,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
                     };
                     return result;
                 }
    -            unreachable // put into a full map
    +            unreachable; // put into a full map
             }
     
             fn internalGet(hm: &Self, key: K) -> ?&Entry {
    @@ -228,7 +228,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
             fn keyToIndex(hm: &Self, key: K) -> usize {
                 return usize(hash(key)) % hm.entries.len;
             }
    -    }
    +    };
     }
     
     test "basicHashMapTest" {
    @@ -251,9 +251,9 @@ test "basicHashMapTest" {
     }
     
     fn hash_i32(x: i32) -> u32 {
    -    @bitCast(u32, x)
    +    return @bitCast(u32, x);
     }
     
     fn eql_i32(a: i32, b: i32) -> bool {
    -    a == b
    +    return a == b;
     }
    diff --git a/std/heap.zig b/std/heap.zig
    index d54d921856..605eddb40b 100644
    --- a/std/heap.zig
    +++ b/std/heap.zig
    @@ -17,22 +17,21 @@ pub var c_allocator = Allocator {
     };
     
     fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
    -    if (c.malloc(usize(n))) |buf| {
    +    return if (c.malloc(usize(n))) |buf|
             @ptrCast(&u8, buf)[0..n]
    -    } else {
    -        error.OutOfMemory
    -    }
    +    else
    +        error.OutOfMemory;
     }
     
     fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
         if (new_size <= old_mem.len) {
    -        old_mem[0..new_size]
    +        return old_mem[0..new_size];
         } else {
             const old_ptr = @ptrCast(&c_void, old_mem.ptr);
             if (c.realloc(old_ptr, usize(new_size))) |buf| {
    -            @ptrCast(&u8, buf)[0..new_size]
    +            return @ptrCast(&u8, buf)[0..new_size];
             } else {
    -            error.OutOfMemory
    +            return error.OutOfMemory;
             }
         }
     }
    diff --git a/std/io.zig b/std/io.zig
    index 0ba3d06a01..cbf2e0c216 100644
    --- a/std/io.zig
    +++ b/std/io.zig
    @@ -50,35 +50,32 @@ error Unseekable;
     error EndOfFile;
     
     pub fn getStdErr() -> %File {
    -    const handle = if (is_windows) {
    +    const handle = if (is_windows)
             %return os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
    -    } else if (is_posix) {
    +    else if (is_posix)
             system.STDERR_FILENO
    -    } else {
    -        unreachable
    -    };
    +    else
    +        unreachable;
         return File.openHandle(handle);
     }
     
     pub fn getStdOut() -> %File {
    -    const handle = if (is_windows) {
    +    const handle = if (is_windows)
             %return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
    -    } else if (is_posix) {
    +    else if (is_posix)
             system.STDOUT_FILENO
    -    } else {
    -        unreachable
    -    };
    +    else
    +        unreachable;
         return File.openHandle(handle);
     }
     
     pub fn getStdIn() -> %File {
    -    const handle = if (is_windows) {
    +    const handle = if (is_windows)
             %return os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
    -    } else if (is_posix) {
    +    else if (is_posix)
             system.STDIN_FILENO
    -    } else {
    -        unreachable
    -    };
    +    else
    +        unreachable;
         return File.openHandle(handle);
     }
     
    @@ -261,7 +258,7 @@ pub const File = struct {
                         system.EBADF => error.BadFd,
                         system.ENOMEM => error.SystemResources,
                         else => os.unexpectedErrorPosix(err),
    -                }
    +                };
                 }
     
                 return usize(stat.size);
    diff --git a/std/linked_list.zig b/std/linked_list.zig
    index cbcef793de..f4b6d274c9 100644
    --- a/std/linked_list.zig
    +++ b/std/linked_list.zig
    @@ -5,7 +5,7 @@ const Allocator = mem.Allocator;
     
     /// Generic doubly linked list.
     pub fn LinkedList(comptime T: type) -> type {
    -    struct {
    +    return struct {
             const Self = this;
     
             /// Node inside the linked list wrapping the actual data.
    @@ -15,11 +15,11 @@ pub fn LinkedList(comptime T: type) -> type {
                 data: T,
     
                 pub fn init(data: &const T) -> Node {
    -                Node {
    +                return Node {
                         .prev = null,
                         .next = null,
                         .data = *data,
    -                }
    +                };
                 }
             };
     
    @@ -32,11 +32,11 @@ pub fn LinkedList(comptime T: type) -> type {
             /// Returns:
             ///     An empty linked list.
             pub fn init() -> Self {
    -            Self {
    +            return Self {
                     .first = null,
                     .last  = null,
                     .len   = 0,
    -            }
    +            };
             }
     
             /// Insert a new node after an existing one.
    @@ -166,7 +166,7 @@ pub fn LinkedList(comptime T: type) -> type {
             /// Returns:
             ///     A pointer to the new node.
             pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node {
    -            allocator.create(Node)
    +            return allocator.create(Node);
             }
     
             /// Deallocate a node.
    @@ -191,7 +191,7 @@ pub fn LinkedList(comptime T: type) -> type {
                 *node = Node.init(data);
                 return node;
             }
    -    }
    +    };
     }
     
     test "basic linked list test" {
    diff --git a/std/math/acos.zig b/std/math/acos.zig
    index 941643db82..ae7afce032 100644
    --- a/std/math/acos.zig
    +++ b/std/math/acos.zig
    @@ -7,11 +7,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn acos(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(acos32, x),
             f64 => @inlineCall(acos64, x),
             else => @compileError("acos not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn r32(z: f32) -> f32 {
    @@ -22,7 +22,7 @@ fn r32(z: f32) -> f32 {
     
         const p = z * (pS0 + z * (pS1 + z * pS2));
         const q = 1.0 + z * qS1;
    -    p / q
    +    return p / q;
     }
     
     fn acos32(x: f32) -> f32 {
    @@ -69,7 +69,7 @@ fn acos32(x: f32) -> f32 {
         const df = @bitCast(f32, jx & 0xFFFFF000);
         const c = (z - df * df) / (s + df);
         const w = r32(z) * s + c;
    -    2 * (df + w)
    +    return 2 * (df + w);
     }
     
     fn r64(z: f64) -> f64 {
    @@ -86,7 +86,7 @@ fn r64(z: f64) -> f64 {
     
         const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
         const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
    -    p / q
    +    return p / q;
     }
     
     fn acos64(x: f64) -> f64 {
    @@ -138,7 +138,7 @@ fn acos64(x: f64) -> f64 {
         const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
         const c = (z - df * df) / (s + df);
         const w = r64(z) * s + c;
    -    2 * (df + w)
    +    return 2 * (df + w);
     }
     
     test "math.acos" {
    diff --git a/std/math/acosh.zig b/std/math/acosh.zig
    index 9f43edeb5d..0fdf9e41e0 100644
    --- a/std/math/acosh.zig
    +++ b/std/math/acosh.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn acosh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(acosh32, x),
             f64 => @inlineCall(acosh64, x),
             else => @compileError("acosh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // acosh(x) = log(x + sqrt(x * x - 1))
    @@ -23,15 +23,15 @@ fn acosh32(x: f32) -> f32 {
     
         // |x| < 2, invalid if x < 1 or nan
         if (i < 0x3F800000 + (1 << 23)) {
    -        math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)))
    +        return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
         }
         // |x| < 0x1p12
         else if (i < 0x3F800000 + (12 << 23)) {
    -        math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)))
    +        return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
         }
         // |x| >= 0x1p12
         else {
    -        math.ln(x) + 0.693147180559945309417232121458176568
    +        return math.ln(x) + 0.693147180559945309417232121458176568;
         }
     }
     
    @@ -41,15 +41,15 @@ fn acosh64(x: f64) -> f64 {
     
         // |x| < 2, invalid if x < 1 or nan
         if (e < 0x3FF + 1) {
    -        math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)))
    +        return math.log1p(x - 1 + math.sqrt((x - 1) * (x - 1) + 2 * (x - 1)));
         }
         // |x| < 0x1p26
         else if (e < 0x3FF + 26) {
    -        math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)))
    +        return math.ln(2 * x - 1 / (x + math.sqrt(x * x - 1)));
         }
         // |x| >= 0x1p26 or nan
         else {
    -        math.ln(x) + 0.693147180559945309417232121458176568
    +        return math.ln(x) + 0.693147180559945309417232121458176568;
         }
     }
     
    diff --git a/std/math/asin.zig b/std/math/asin.zig
    index b0368b5d66..11aad04107 100644
    --- a/std/math/asin.zig
    +++ b/std/math/asin.zig
    @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn asin(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(asin32, x),
             f64 => @inlineCall(asin64, x),
             else => @compileError("asin not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn r32(z: f32) -> f32 {
    @@ -23,7 +23,7 @@ fn r32(z: f32) -> f32 {
     
         const p = z * (pS0 + z * (pS1 + z * pS2));
         const q = 1.0 + z * qS1;
    -    p / q
    +    return p / q;
     }
     
     fn asin32(x: f32) -> f32 {
    @@ -58,9 +58,9 @@ fn asin32(x: f32) -> f32 {
         const fx = pio2 - 2 * (s + s * r32(z));
     
         if (hx >> 31 != 0) {
    -        -fx
    +        return -fx;
         } else {
    -        fx
    +        return fx;
         }
     }
     
    @@ -78,7 +78,7 @@ fn r64(z: f64) -> f64 {
     
         const p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
         const q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
    -    p / q
    +    return p / q;
     }
     
     fn asin64(x: f64) -> f64 {
    @@ -119,7 +119,7 @@ fn asin64(x: f64) -> f64 {
     
         // |x| > 0.975
         if (ix >= 0x3FEF3333) {
    -        fx = pio2_hi - 2 * (s + s * r)
    +        fx = pio2_hi - 2 * (s + s * r);
         } else {
             const jx = @bitCast(u64, s);
             const df = @bitCast(f64, jx & 0xFFFFFFFF00000000);
    @@ -128,9 +128,9 @@ fn asin64(x: f64) -> f64 {
         }
     
         if (hx >> 31 != 0) {
    -        -fx
    +        return -fx;
         } else {
    -        fx
    +        return fx;
         }
     }
     
    diff --git a/std/math/asinh.zig b/std/math/asinh.zig
    index dab047036a..eda7e15861 100644
    --- a/std/math/asinh.zig
    +++ b/std/math/asinh.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn asinh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(asinh32, x),
             f64 => @inlineCall(asinh64, x),
             else => @compileError("asinh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // asinh(x) = sign(x) * log(|x| + sqrt(x * x + 1)) ~= x - x^3/6 + o(x^5)
    @@ -46,7 +46,7 @@ fn asinh32(x: f32) -> f32 {
             math.forceEval(x + 0x1.0p120);
         }
     
    -    if (s != 0) -rx else rx
    +    return if (s != 0) -rx else rx;
     }
     
     fn asinh64(x: f64) -> f64 {
    @@ -77,7 +77,7 @@ fn asinh64(x: f64) -> f64 {
             math.forceEval(x + 0x1.0p120);
         }
     
    -    if (s != 0) -rx else rx
    +    return if (s != 0) -rx else rx;
     }
     
     test "math.asinh" {
    diff --git a/std/math/atan.zig b/std/math/atan.zig
    index 5f3e207960..4527f6bf28 100644
    --- a/std/math/atan.zig
    +++ b/std/math/atan.zig
    @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn atan(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(atan32, x),
             f64 => @inlineCall(atan64, x),
             else => @compileError("atan not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn atan32(x_: f32) -> f32 {
    @@ -100,10 +100,10 @@ fn atan32(x_: f32) -> f32 {
         const s2 = w * (aT[1] + w * aT[3]);
     
         if (id == null) {
    -        x - x * (s1 + s2)
    +        return x - x * (s1 + s2);
         } else {
             const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
    -        if (sign != 0) -zz else zz
    +        return if (sign != 0) -zz else zz;
         }
     }
     
    @@ -199,10 +199,10 @@ fn atan64(x_: f64) -> f64 {
         const s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
     
         if (id == null) {
    -        x - x * (s1 + s2)
    +        return x - x * (s1 + s2);
         } else {
             const zz = atanhi[??id] - ((x * (s1 + s2) - atanlo[??id]) - x);
    -        if (sign != 0) -zz else zz
    +        return if (sign != 0) -zz else zz;
         }
     }
     
    diff --git a/std/math/atan2.zig b/std/math/atan2.zig
    index 0e566837ce..9124952b74 100644
    --- a/std/math/atan2.zig
    +++ b/std/math/atan2.zig
    @@ -22,11 +22,11 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     fn atan2(comptime T: type, x: T, y: T) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(atan2_32, x, y),
             f64 => @inlineCall(atan2_64, x, y),
             else => @compileError("atan2 not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn atan2_32(y: f32, x: f32) -> f32 {
    @@ -97,11 +97,11 @@ fn atan2_32(y: f32, x: f32) -> f32 {
         }
     
         // z = atan(|y / x|) with correct underflow
    -    var z = {
    +    var z = z: {
             if ((m & 2) != 0 and iy + (26 << 23) < ix) {
    -            0.0
    +            break :z 0.0;
             } else {
    -            math.atan(math.fabs(y / x))
    +            break :z math.atan(math.fabs(y / x));
             }
         };
     
    @@ -187,11 +187,11 @@ fn atan2_64(y: f64, x: f64) -> f64 {
         }
     
         // z = atan(|y / x|) with correct underflow
    -    var z = {
    +    var z = z: {
             if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
    -            0.0
    +            break :z 0.0;
             } else {
    -            math.atan(math.fabs(y / x))
    +            break :z math.atan(math.fabs(y / x));
             }
         };
     
    diff --git a/std/math/atanh.zig b/std/math/atanh.zig
    index 8fe5ab55a7..2f87efbbd3 100644
    --- a/std/math/atanh.zig
    +++ b/std/math/atanh.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn atanh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(atanh_32, x),
             f64 => @inlineCall(atanh_64, x),
             else => @compileError("atanh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // atanh(x) = log((1 + x) / (1 - x)) / 2 = log1p(2x / (1 - x)) / 2 ~= x + x^3 / 3 + o(x^5)
    @@ -32,7 +32,7 @@ fn atanh_32(x: f32) -> f32 {
             if (u < 0x3F800000 - (32 << 23)) {
                 // underflow
                 if (u < (1 << 23)) {
    -                math.forceEval(y * y)
    +                math.forceEval(y * y);
                 }
             }
             // |x| < 0.5
    @@ -43,7 +43,7 @@ fn atanh_32(x: f32) -> f32 {
             y = 0.5 * math.log1p(2 * (y / (1 - y)));
         }
     
    -    if (s != 0) -y else y
    +    return if (s != 0) -y else y;
     }
     
     fn atanh_64(x: f64) -> f64 {
    @@ -72,7 +72,7 @@ fn atanh_64(x: f64) -> f64 {
             y = 0.5 * math.log1p(2 * (y / (1 - y)));
         }
     
    -    if (s != 0) -y else y
    +    return if (s != 0) -y else y;
     }
     
     test "math.atanh" {
    diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig
    index 273939c6b6..ff353655b5 100644
    --- a/std/math/cbrt.zig
    +++ b/std/math/cbrt.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn cbrt(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(cbrt32, x),
             f64 => @inlineCall(cbrt64, x),
             else => @compileError("cbrt not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn cbrt32(x: f32) -> f32 {
    @@ -53,7 +53,7 @@ fn cbrt32(x: f32) -> f32 {
         r = t * t * t;
         t = t * (f64(x) + x + r) / (x + r + r);
     
    -    f32(t)
    +    return f32(t);
     }
     
     fn cbrt64(x: f64) -> f64 {
    @@ -109,7 +109,7 @@ fn cbrt64(x: f64) -> f64 {
         var w = t + t;
         q = (q - t) / (w + q);
     
    -    t + t * q
    +    return t + t * q;
     }
     
     test "math.cbrt" {
    diff --git a/std/math/ceil.zig b/std/math/ceil.zig
    index 2c7b28cc93..a8db486f92 100644
    --- a/std/math/ceil.zig
    +++ b/std/math/ceil.zig
    @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn ceil(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(ceil32, x),
             f64 => @inlineCall(ceil64, x),
             else => @compileError("ceil not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn ceil32(x: f32) -> f32 {
    @@ -39,13 +39,13 @@ fn ceil32(x: f32) -> f32 {
                 u += m;
             }
             u &= ~m;
    -        @bitCast(f32, u)
    +        return @bitCast(f32, u);
         } else {
             math.forceEval(x + 0x1.0p120);
             if (u >> 31 != 0) {
                 return -0.0;
             } else {
    -            1.0
    +            return 1.0;
             }
         }
     }
    @@ -70,14 +70,14 @@ fn ceil64(x: f64) -> f64 {
         if (e <= 0x3FF-1) {
             math.forceEval(y);
             if (u >> 63 != 0) {
    -            return -0.0;    // Compiler requires return.
    +            return -0.0;
             } else {
    -            1.0
    +            return 1.0;
             }
         } else if (y < 0) {
    -        x + y + 1
    +        return x + y + 1;
         } else {
    -        x + y
    +        return x + y;
         }
     }
     
    diff --git a/std/math/copysign.zig b/std/math/copysign.zig
    index 109ee8c632..12e092c9ab 100644
    --- a/std/math/copysign.zig
    +++ b/std/math/copysign.zig
    @@ -2,11 +2,11 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     pub fn copysign(comptime T: type, x: T, y: T) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(copysign32, x, y),
             f64 => @inlineCall(copysign64, x, y),
             else => @compileError("copysign not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn copysign32(x: f32, y: f32) -> f32 {
    @@ -15,7 +15,7 @@ fn copysign32(x: f32, y: f32) -> f32 {
     
         const h1 = ux & (@maxValue(u32) / 2);
         const h2 = uy & (u32(1) << 31);
    -    @bitCast(f32, h1 | h2)
    +    return @bitCast(f32, h1 | h2);
     }
     
     fn copysign64(x: f64, y: f64) -> f64 {
    @@ -24,7 +24,7 @@ fn copysign64(x: f64, y: f64) -> f64 {
     
         const h1 = ux & (@maxValue(u64) / 2);
         const h2 = uy & (u64(1) << 63);
    -    @bitCast(f64, h1 | h2)
    +    return @bitCast(f64, h1 | h2);
     }
     
     test "math.copysign" {
    diff --git a/std/math/cos.zig b/std/math/cos.zig
    index 4b5c9193c3..285a2e538b 100644
    --- a/std/math/cos.zig
    +++ b/std/math/cos.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn cos(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(cos32, x),
             f64 => @inlineCall(cos64, x),
             else => @compileError("cos not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // sin polynomial coefficients
    @@ -73,18 +73,18 @@ fn cos32(x_: f32) -> f32 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    const r = {
    +    const r = r: {
             if (j == 1 or j == 2) {
    -            z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
    +            break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
             } else {
    -            1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
    +            break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
             }
         };
     
         if (sign) {
    -        -r
    +        return -r;
         } else {
    -        r
    +        return r;
         }
     }
     
    @@ -124,18 +124,18 @@ fn cos64(x_: f64) -> f64 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    const r = {
    +    const r = r: {
             if (j == 1 or j == 2) {
    -            z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
    +            break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
             } else {
    -            1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
    +            break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
             }
         };
     
         if (sign) {
    -        -r
    +        return -r;
         } else {
    -        r
    +        return r;
         }
     }
     
    diff --git a/std/math/cosh.zig b/std/math/cosh.zig
    index 34c647eaad..f7fea99bcc 100644
    --- a/std/math/cosh.zig
    +++ b/std/math/cosh.zig
    @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn cosh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(cosh32, x),
             f64 => @inlineCall(cosh64, x),
             else => @compileError("cosh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // cosh(x) = (exp(x) + 1 / exp(x)) / 2
    @@ -43,7 +43,7 @@ fn cosh32(x: f32) -> f32 {
         }
     
         // |x| > log(FLT_MAX) or nan
    -    expo2(ax)
    +    return expo2(ax);
     }
     
     fn cosh64(x: f64) -> f64 {
    @@ -76,7 +76,7 @@ fn cosh64(x: f64) -> f64 {
         }
     
         // |x| > log(CBL_MAX) or nan
    -    expo2(ax)
    +    return expo2(ax);
     }
     
     test "math.cosh" {
    diff --git a/std/math/exp.zig b/std/math/exp.zig
    index 87c0a1882e..e51221a74a 100644
    --- a/std/math/exp.zig
    +++ b/std/math/exp.zig
    @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn exp(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(exp32, x),
             f64 => @inlineCall(exp64, x),
             else => @compileError("exp not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn exp32(x_: f32) -> f32 {
    @@ -86,9 +86,9 @@ fn exp32(x_: f32) -> f32 {
         const y = 1 + (x * c / (2 - c) - lo + hi);
     
         if (k == 0) {
    -        y
    +        return y;
         } else {
    -        math.scalbn(y, k)
    +        return math.scalbn(y, k);
         }
     }
     
    @@ -172,9 +172,9 @@ fn exp64(x_: f64) -> f64 {
         const y = 1 + (x * c / (2 - c) - lo + hi);
     
         if (k == 0) {
    -        y
    +        return y;
         } else {
    -        math.scalbn(y, k)
    +        return math.scalbn(y, k);
         }
     }
     
    diff --git a/std/math/exp2.zig b/std/math/exp2.zig
    index 111c1dad64..e867aabe23 100644
    --- a/std/math/exp2.zig
    +++ b/std/math/exp2.zig
    @@ -8,11 +8,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn exp2(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(exp2_32, x),
             f64 => @inlineCall(exp2_64, x),
             else => @compileError("exp2 not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     const exp2ft = []const f64 {
    @@ -88,7 +88,7 @@ fn exp2_32(x: f32) -> f32 {
         var r: f64 = exp2ft[i0];
         const t: f64 = r * z;
         r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4);
    -    f32(r * uk)
    +    return f32(r * uk);
     }
     
     const exp2dt = []f64 {
    @@ -414,7 +414,7 @@ fn exp2_64(x: f64) -> f64 {
         z -= exp2dt[2 * i0 + 1];
         const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5))));
     
    -    math.scalbn(r, ik)
    +    return math.scalbn(r, ik);
     }
     
     test "math.exp2" {
    diff --git a/std/math/expm1.zig b/std/math/expm1.zig
    index ef0b2766b1..14a69958e8 100644
    --- a/std/math/expm1.zig
    +++ b/std/math/expm1.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn expm1(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(expm1_32, x),
             f64 => @inlineCall(expm1_64, x),
             else => @compileError("exp1m not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn expm1_32(x_: f32) -> f32 {
    diff --git a/std/math/expo2.zig b/std/math/expo2.zig
    index e0d8a8130d..93111391a2 100644
    --- a/std/math/expo2.zig
    +++ b/std/math/expo2.zig
    @@ -2,11 +2,11 @@ const math = @import("index.zig");
     
     pub fn expo2(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => expo2f(x),
             f64 => expo2d(x),
             else => @compileError("expo2 not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn expo2f(x: f32) -> f32 {
    @@ -15,7 +15,7 @@ fn expo2f(x: f32) -> f32 {
     
         const u = (0x7F + k / 2) << 23;
         const scale = @bitCast(f32, u);
    -    math.exp(x - kln2) * scale * scale
    +    return math.exp(x - kln2) * scale * scale;
     }
     
     fn expo2d(x: f64) -> f64 {
    @@ -24,5 +24,5 @@ fn expo2d(x: f64) -> f64 {
     
         const u = (0x3FF + k / 2) << 20;
         const scale = @bitCast(f64, u64(u) << 32);
    -    math.exp(x - kln2) * scale * scale
    +    return math.exp(x - kln2) * scale * scale;
     }
    diff --git a/std/math/fabs.zig b/std/math/fabs.zig
    index e9bd3eb689..58244f4f2e 100644
    --- a/std/math/fabs.zig
    +++ b/std/math/fabs.zig
    @@ -8,23 +8,23 @@ const assert = @import("../debug.zig").assert;
     
     pub fn fabs(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(fabs32, x),
             f64 => @inlineCall(fabs64, x),
             else => @compileError("fabs not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn fabs32(x: f32) -> f32 {
         var u = @bitCast(u32, x);
         u &= 0x7FFFFFFF;
    -    @bitCast(f32, u)
    +    return @bitCast(f32, u);
     }
     
     fn fabs64(x: f64) -> f64 {
         var u = @bitCast(u64, x);
         u &= @maxValue(u64) >> 1;
    -    @bitCast(f64, u)
    +    return @bitCast(f64, u);
     }
     
     test "math.fabs" {
    diff --git a/std/math/floor.zig b/std/math/floor.zig
    index 85ee2b4923..875070397d 100644
    --- a/std/math/floor.zig
    +++ b/std/math/floor.zig
    @@ -10,11 +10,11 @@ const math = @import("index.zig");
     
     pub fn floor(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(floor32, x),
             f64 => @inlineCall(floor64, x),
             else => @compileError("floor not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn floor32(x: f32) -> f32 {
    @@ -40,13 +40,13 @@ fn floor32(x: f32) -> f32 {
             if (u >> 31 != 0) {
                 u += m;
             }
    -        @bitCast(f32, u & ~m)
    +        return @bitCast(f32, u & ~m);
         } else {
             math.forceEval(x + 0x1.0p120);
             if (u >> 31 == 0) {
    -            return 0.0; // Compiler requires return
    +            return 0.0;
             } else {
    -            -1.0
    +            return -1.0;
             }
         }
     }
    @@ -71,14 +71,14 @@ fn floor64(x: f64) -> f64 {
         if (e <= 0x3FF-1) {
             math.forceEval(y);
             if (u >> 63 != 0) {
    -            return -1.0;    // Compiler requires return.
    +            return -1.0;
             } else {
    -            0.0
    +            return 0.0;
             }
         } else if (y > 0) {
    -        x + y - 1
    +        return x + y - 1;
         } else {
    -        x + y
    +        return x + y;
         }
     }
     
    diff --git a/std/math/fma.zig b/std/math/fma.zig
    index 8dbbc39ed0..c870dfd293 100644
    --- a/std/math/fma.zig
    +++ b/std/math/fma.zig
    @@ -2,11 +2,11 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(fma32, x, y, z),
             f64 => @inlineCall(fma64, x, y ,z),
             else => @compileError("fma not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn fma32(x: f32, y: f32, z: f32) -> f32 {
    @@ -16,10 +16,10 @@ fn fma32(x: f32, y: f32, z: f32) -> f32 {
         const e = (u >> 52) & 0x7FF;
     
         if ((u & 0x1FFFFFFF) != 0x10000000 or e == 0x7FF or xy_z - xy == z) {
    -        f32(xy_z)
    +        return f32(xy_z);
         } else {
             // TODO: Handle inexact case with double-rounding
    -        f32(xy_z)
    +        return f32(xy_z);
         }
     }
     
    @@ -64,9 +64,9 @@ fn fma64(x: f64, y: f64, z: f64) -> f64 {
     
         const adj = add_adjusted(r.lo, xy.lo);
         if (spread + math.ilogb(r.hi) > -1023) {
    -        math.scalbn(r.hi + adj, spread)
    +        return math.scalbn(r.hi + adj, spread);
         } else {
    -        add_and_denorm(r.hi, adj, spread)
    +        return add_and_denorm(r.hi, adj, spread);
         }
     }
     
    @@ -77,7 +77,7 @@ fn dd_add(a: f64, b: f64) -> dd {
         ret.hi = a + b;
         const s = ret.hi - a;
         ret.lo = (a - (ret.hi - s)) + (b - s);
    -    ret
    +    return ret;
     }
     
     fn dd_mul(a: f64, b: f64) -> dd {
    @@ -99,7 +99,7 @@ fn dd_mul(a: f64, b: f64) -> dd {
     
         ret.hi = p + q;
         ret.lo = p - ret.hi + q + la * lb;
    -    ret
    +    return ret;
     }
     
     fn add_adjusted(a: f64, b: f64) -> f64 {
    @@ -113,7 +113,7 @@ fn add_adjusted(a: f64, b: f64) -> f64 {
                 sum.hi = @bitCast(f64, uhii);
             }
         }
    -    sum.hi
    +    return sum.hi;
     }
     
     fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
    @@ -127,7 +127,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) -> f64 {
                 sum.hi = @bitCast(f64, uhii);
             }
         }
    -    math.scalbn(sum.hi, scale)
    +    return math.scalbn(sum.hi, scale);
     }
     
     test "math.fma" {
    diff --git a/std/math/frexp.zig b/std/math/frexp.zig
    index a40a6dcc39..e648555e31 100644
    --- a/std/math/frexp.zig
    +++ b/std/math/frexp.zig
    @@ -8,21 +8,21 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     fn frexp_result(comptime T: type) -> type {
    -    struct {
    +    return struct {
             significand: T,
             exponent: i32,
    -    }
    +    };
     }
     pub const frexp32_result = frexp_result(f32);
     pub const frexp64_result = frexp_result(f64);
     
     pub fn frexp(x: var) -> frexp_result(@typeOf(x)) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(frexp32, x),
             f64 => @inlineCall(frexp64, x),
             else => @compileError("frexp not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn frexp32(x: f32) -> frexp32_result {
    @@ -59,7 +59,7 @@ fn frexp32(x: f32) -> frexp32_result {
         y &= 0x807FFFFF;
         y |= 0x3F000000;
         result.significand = @bitCast(f32, y);
    -    result
    +    return result;
     }
     
     fn frexp64(x: f64) -> frexp64_result {
    @@ -96,7 +96,7 @@ fn frexp64(x: f64) -> frexp64_result {
         y &= 0x800FFFFFFFFFFFFF;
         y |= 0x3FE0000000000000;
         result.significand = @bitCast(f64, y);
    -    result
    +    return result;
     }
     
     test "math.frexp" {
    diff --git a/std/math/hypot.zig b/std/math/hypot.zig
    index ee8ce0f518..68794e24fe 100644
    --- a/std/math/hypot.zig
    +++ b/std/math/hypot.zig
    @@ -9,11 +9,11 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     pub fn hypot(comptime T: type, x: T, y: T) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(hypot32, x, y),
             f64 => @inlineCall(hypot64, x, y),
             else => @compileError("hypot not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn hypot32(x: f32, y: f32) -> f32 {
    @@ -48,7 +48,7 @@ fn hypot32(x: f32, y: f32) -> f32 {
             yy *= 0x1.0p-90;
         }
     
    -    z * math.sqrt(f32(f64(x) * x + f64(y) * y))
    +    return z * math.sqrt(f32(f64(x) * x + f64(y) * y));
     }
     
     fn sq(hi: &f64, lo: &f64, x: f64) {
    @@ -109,7 +109,7 @@ fn hypot64(x: f64, y: f64) -> f64 {
         sq(&hx, &lx, x);
         sq(&hy, &ly, y);
     
    -    z * math.sqrt(ly + lx + hy + hx)
    +    return z * math.sqrt(ly + lx + hy + hx);
     }
     
     test "math.hypot" {
    diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig
    index 2a0ea7fc5f..e056ceb097 100644
    --- a/std/math/ilogb.zig
    +++ b/std/math/ilogb.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn ilogb(x: var) -> i32 {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(ilogb32, x),
             f64 => @inlineCall(ilogb64, x),
             else => @compileError("ilogb not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // NOTE: Should these be exposed publically?
    @@ -53,7 +53,7 @@ fn ilogb32(x: f32) -> i32 {
             }
         }
     
    -    e - 0x7F
    +    return e - 0x7F;
     }
     
     fn ilogb64(x: f64) -> i32 {
    @@ -88,7 +88,7 @@ fn ilogb64(x: f64) -> i32 {
             }
         }
     
    -    e - 0x3FF
    +    return e - 0x3FF;
     }
     
     test "math.ilogb" {
    diff --git a/std/math/index.zig b/std/math/index.zig
    index 029f2836b7..1991864f69 100644
    --- a/std/math/index.zig
    +++ b/std/math/index.zig
    @@ -36,7 +36,7 @@ pub const inf = @import("inf.zig").inf;
     
     pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) -> bool {
         assert(@typeId(T) == TypeId.Float);
    -    fabs(x - y) < epsilon
    +    return fabs(x - y) < epsilon;
     }
     
     // TODO: Hide the following in an internal module.
    @@ -175,7 +175,7 @@ test "math" {
     
     
     pub fn min(x: var, y: var) -> @typeOf(x + y) {
    -    if (x < y) x else y
    +    return if (x < y) x else y;
     }
     
     test "math.min" {
    @@ -183,7 +183,7 @@ test "math.min" {
     }
     
     pub fn max(x: var, y: var) -> @typeOf(x + y) {
    -    if (x > y) x else y
    +    return if (x > y) x else y;
     }
     
     test "math.max" {
    @@ -193,19 +193,19 @@ test "math.max" {
     error Overflow;
     pub fn mul(comptime T: type, a: T, b: T) -> %T {
         var answer: T = undefined;
    -    if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer
    +    return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
     }
     
     error Overflow;
     pub fn add(comptime T: type, a: T, b: T) -> %T {
         var answer: T = undefined;
    -    if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer
    +    return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
     }
     
     error Overflow;
     pub fn sub(comptime T: type, a: T, b: T) -> %T {
         var answer: T = undefined;
    -    if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer
    +    return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
     }
     
     pub fn negate(x: var) -> %@typeOf(x) {
    @@ -215,7 +215,7 @@ pub fn negate(x: var) -> %@typeOf(x) {
     error Overflow;
     pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T {
         var answer: T = undefined;
    -    if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer
    +    return if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer;
     }
     
     /// Shifts left. Overflowed bits are truncated.
    @@ -267,7 +267,7 @@ test "math.shr" {
     }
     
     pub fn Log2Int(comptime T: type) -> type {
    -    @IntType(false, log2(T.bit_count))
    +    return @IntType(false, log2(T.bit_count));
     }
     
     test "math overflow functions" {
    diff --git a/std/math/inf.zig b/std/math/inf.zig
    index ed559c313e..546e6f3af8 100644
    --- a/std/math/inf.zig
    +++ b/std/math/inf.zig
    @@ -2,9 +2,9 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     pub fn inf(comptime T: type) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @bitCast(f32, math.inf_u32),
             f64 => @bitCast(f64, math.inf_u64),
             else => @compileError("inf not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
    diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig
    index 6dbf984721..d44d373cf1 100644
    --- a/std/math/isfinite.zig
    +++ b/std/math/isfinite.zig
    @@ -6,11 +6,11 @@ pub fn isFinite(x: var) -> bool {
         switch (T) {
             f32 => {
                 const bits = @bitCast(u32, x);
    -            bits & 0x7FFFFFFF < 0x7F800000
    +            return bits & 0x7FFFFFFF < 0x7F800000;
             },
             f64 => {
                 const bits = @bitCast(u64, x);
    -            bits & (@maxValue(u64) >> 1) < (0x7FF << 52)
    +            return bits & (@maxValue(u64) >> 1) < (0x7FF << 52);
             },
             else => {
                 @compileError("isFinite not implemented for " ++ @typeName(T));
    diff --git a/std/math/isinf.zig b/std/math/isinf.zig
    index b388fabf10..98c90e72a9 100644
    --- a/std/math/isinf.zig
    +++ b/std/math/isinf.zig
    @@ -6,11 +6,11 @@ pub fn isInf(x: var) -> bool {
         switch (T) {
             f32 => {
                 const bits = @bitCast(u32, x);
    -            bits & 0x7FFFFFFF == 0x7F800000
    +            return bits & 0x7FFFFFFF == 0x7F800000;
             },
             f64 => {
                 const bits = @bitCast(u64, x);
    -            bits & (@maxValue(u64) >> 1) == (0x7FF << 52)
    +            return bits & (@maxValue(u64) >> 1) == (0x7FF << 52);
             },
             else => {
                 @compileError("isInf not implemented for " ++ @typeName(T));
    @@ -22,10 +22,10 @@ pub fn isPositiveInf(x: var) -> bool {
         const T = @typeOf(x);
         switch (T) {
             f32 => {
    -            @bitCast(u32, x) == 0x7F800000
    +            return @bitCast(u32, x) == 0x7F800000;
             },
             f64 => {
    -            @bitCast(u64, x) == 0x7FF << 52
    +            return @bitCast(u64, x) == 0x7FF << 52;
             },
             else => {
                 @compileError("isPositiveInf not implemented for " ++ @typeName(T));
    @@ -37,10 +37,10 @@ pub fn isNegativeInf(x: var) -> bool {
         const T = @typeOf(x);
         switch (T) {
             f32 => {
    -            @bitCast(u32, x) == 0xFF800000
    +            return @bitCast(u32, x) == 0xFF800000;
             },
             f64 => {
    -            @bitCast(u64, x) == 0xFFF << 52
    +            return @bitCast(u64, x) == 0xFFF << 52;
             },
             else => {
                 @compileError("isNegativeInf not implemented for " ++ @typeName(T));
    diff --git a/std/math/isnan.zig b/std/math/isnan.zig
    index 8bcb200a6a..e996a72693 100644
    --- a/std/math/isnan.zig
    +++ b/std/math/isnan.zig
    @@ -6,11 +6,11 @@ pub fn isNan(x: var) -> bool {
         switch (T) {
             f32 => {
                 const bits = @bitCast(u32, x);
    -            bits & 0x7FFFFFFF > 0x7F800000
    +            return bits & 0x7FFFFFFF > 0x7F800000;
             },
             f64 => {
                 const bits = @bitCast(u64, x);
    -            (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52)
    +            return (bits & (@maxValue(u64) >> 1)) > (u64(0x7FF) << 52);
             },
             else => {
                 @compileError("isNan not implemented for " ++ @typeName(T));
    @@ -21,7 +21,7 @@ pub fn isNan(x: var) -> bool {
     // Note: A signalling nan is identical to a standard right now by may have a different bit
     // representation in the future when required.
     pub fn isSignalNan(x: var) -> bool {
    -    isNan(x)
    +    return isNan(x);
     }
     
     test "math.isNan" {
    diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig
    index b212d204de..f815c2680b 100644
    --- a/std/math/isnormal.zig
    +++ b/std/math/isnormal.zig
    @@ -6,11 +6,11 @@ pub fn isNormal(x: var) -> bool {
         switch (T) {
             f32 => {
                 const bits = @bitCast(u32, x);
    -            (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000
    +            return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
             },
             f64 => {
                 const bits = @bitCast(u64, x);
    -            (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53)
    +            return (bits + (1 << 52)) & (@maxValue(u64) >> 1) >= (1 << 53);
             },
             else => {
                 @compileError("isNormal not implemented for " ++ @typeName(T));
    diff --git a/std/math/ln.zig b/std/math/ln.zig
    index 7ced6238ef..4ded89d328 100644
    --- a/std/math/ln.zig
    +++ b/std/math/ln.zig
    @@ -14,7 +14,7 @@ pub fn ln(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
         switch (@typeId(T)) {
             TypeId.FloatLiteral => {
    -            return @typeOf(1.0)(ln_64(x))
    +            return @typeOf(1.0)(ln_64(x));
             },
             TypeId.Float => {
                 return switch (T) {
    @@ -84,7 +84,7 @@ pub fn ln_32(x_: f32) -> f32 {
         const hfsq = 0.5 * f * f;
         const dk = f32(k);
     
    -    s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
    +    return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
     }
     
     pub fn ln_64(x_: f64) -> f64 {
    @@ -116,7 +116,7 @@ pub fn ln_64(x_: f64) -> f64 {
             // subnormal, scale x
             k -= 54;
             x *= 0x1.0p54;
    -        hx = u32(@bitCast(u64, ix) >> 32)
    +        hx = u32(@bitCast(u64, ix) >> 32);
         }
         else if (hx >= 0x7FF00000) {
             return x;
    @@ -142,7 +142,7 @@ pub fn ln_64(x_: f64) -> f64 {
         const R = t2 + t1;
         const dk = f64(k);
     
    -    s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi
    +    return s * (hfsq + R) + dk * ln2_lo - hfsq + f + dk * ln2_hi;
     }
     
     test "math.ln" {
    diff --git a/std/math/log.zig b/std/math/log.zig
    index 075cecc890..1ff226f7e5 100644
    --- a/std/math/log.zig
    +++ b/std/math/log.zig
    @@ -29,7 +29,7 @@ pub fn log(comptime T: type, base: T, x: T) -> T {
                     f32 => return f32(math.ln(f64(x)) / math.ln(f64(base))),
                     f64 => return math.ln(x) / math.ln(f64(base)),
                     else => @compileError("log not implemented for " ++ @typeName(T)),
    -            };
    +            }
             },
     
             else => {
    diff --git a/std/math/log10.zig b/std/math/log10.zig
    index 75e1203ad4..73168dec8d 100644
    --- a/std/math/log10.zig
    +++ b/std/math/log10.zig
    @@ -14,7 +14,7 @@ pub fn log10(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
         switch (@typeId(T)) {
             TypeId.FloatLiteral => {
    -            return @typeOf(1.0)(log10_64(x))
    +            return @typeOf(1.0)(log10_64(x));
             },
             TypeId.Float => {
                 return switch (T) {
    @@ -90,7 +90,7 @@ pub fn log10_32(x_: f32) -> f32 {
         const lo = f - hi - hfsq + s * (hfsq + R);
         const dk = f32(k);
     
    -    dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi
    +    return dk * log10_2lo + (lo + hi) * ivln10lo + lo * ivln10hi + hi * ivln10hi + dk * log10_2hi;
     }
     
     pub fn log10_64(x_: f64) -> f64 {
    @@ -124,7 +124,7 @@ pub fn log10_64(x_: f64) -> f64 {
             // subnormal, scale x
             k -= 54;
             x *= 0x1.0p54;
    -        hx = u32(@bitCast(u64, x) >> 32)
    +        hx = u32(@bitCast(u64, x) >> 32);
         }
         else if (hx >= 0x7FF00000) {
             return x;
    @@ -167,7 +167,7 @@ pub fn log10_64(x_: f64) -> f64 {
         val_lo += (y - ww) + val_hi;
         val_hi = ww;
     
    -    val_lo + val_hi
    +    return val_lo + val_hi;
     }
     
     test "math.log10" {
    diff --git a/std/math/log1p.zig b/std/math/log1p.zig
    index 803726fdcc..433a7c6192 100644
    --- a/std/math/log1p.zig
    +++ b/std/math/log1p.zig
    @@ -11,11 +11,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn log1p(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(log1p_32, x),
             f64 => @inlineCall(log1p_64, x),
             else => @compileError("log1p not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn log1p_32(x: f32) -> f32 {
    @@ -91,7 +91,7 @@ fn log1p_32(x: f32) -> f32 {
         const hfsq = 0.5 * f * f;
         const dk = f32(k);
     
    -    s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
    +    return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
     }
     
     fn log1p_64(x: f64) -> f64 {
    @@ -172,7 +172,7 @@ fn log1p_64(x: f64) -> f64 {
         const R = t2 + t1;
         const dk = f64(k);
     
    -    s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi
    +    return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
     }
     
     test "math.log1p" {
    diff --git a/std/math/log2.zig b/std/math/log2.zig
    index 2199d6bfa1..1b38a9ecee 100644
    --- a/std/math/log2.zig
    +++ b/std/math/log2.zig
    @@ -14,7 +14,7 @@ pub fn log2(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
         switch (@typeId(T)) {
             TypeId.FloatLiteral => {
    -            return @typeOf(1.0)(log2_64(x))
    +            return @typeOf(1.0)(log2_64(x));
             },
             TypeId.Float => {
                 return switch (T) {
    @@ -26,7 +26,7 @@ pub fn log2(x: var) -> @typeOf(x) {
             TypeId.IntLiteral => comptime {
                 var result = 0;
                 var x_shifted = x;
    -            while ({x_shifted >>= 1; x_shifted != 0}) : (result += 1) {}
    +            while (b: {x_shifted >>= 1; break :b x_shifted != 0;}) : (result += 1) {}
                 return result;
             },
             TypeId.Int => {
    @@ -94,7 +94,7 @@ pub fn log2_32(x_: f32) -> f32 {
         u &= 0xFFFFF000;
         hi = @bitCast(f32, u);
         const lo = f - hi - hfsq + s * (hfsq + R);
    -    (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k)
    +    return (lo + hi) * ivln2lo + lo * ivln2hi + hi * ivln2hi + f32(k);
     }
     
     pub fn log2_64(x_: f64) -> f64 {
    @@ -165,7 +165,7 @@ pub fn log2_64(x_: f64) -> f64 {
         val_lo += (y - ww) + val_hi;
         val_hi = ww;
     
    -    val_lo + val_hi
    +    return val_lo + val_hi;
     }
     
     test "math.log2" {
    diff --git a/std/math/modf.zig b/std/math/modf.zig
    index 25eab7f99d..5b78680c51 100644
    --- a/std/math/modf.zig
    +++ b/std/math/modf.zig
    @@ -7,21 +7,21 @@ const math = @import("index.zig");
     const assert = @import("../debug.zig").assert;
     
     fn modf_result(comptime T: type) -> type {
    -    struct {
    +    return struct {
             fpart: T,
             ipart: T,
    -    }
    +    };
     }
     pub const modf32_result = modf_result(f32);
     pub const modf64_result = modf_result(f64);
     
     pub fn modf(x: var) -> modf_result(@typeOf(x)) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(modf32, x),
             f64 => @inlineCall(modf64, x),
             else => @compileError("modf not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn modf32(x: f32) -> modf32_result {
    @@ -66,7 +66,7 @@ fn modf32(x: f32) -> modf32_result {
         const uf = @bitCast(f32, u & ~mask);
         result.ipart = uf;
         result.fpart = x - uf;
    -    result
    +    return result;
     }
     
     fn modf64(x: f64) -> modf64_result {
    @@ -110,7 +110,7 @@ fn modf64(x: f64) -> modf64_result {
         const uf = @bitCast(f64, u & ~mask);
         result.ipart = uf;
         result.fpart = x - uf;
    -    result
    +    return result;
     }
     
     test "math.modf" {
    diff --git a/std/math/nan.zig b/std/math/nan.zig
    index a4899d6b82..e92bb04cb9 100644
    --- a/std/math/nan.zig
    +++ b/std/math/nan.zig
    @@ -1,19 +1,19 @@
     const math = @import("index.zig");
     
     pub fn nan(comptime T: type) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @bitCast(f32, math.nan_u32),
             f64 => @bitCast(f64, math.nan_u64),
             else => @compileError("nan not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // Note: A signalling nan is identical to a standard right now by may have a different bit
     // representation in the future when required.
     pub fn snan(comptime T: type) -> T {
    -    switch (T) {
    +    return switch (T) {
             f32 => @bitCast(f32, math.nan_u32),
             f64 => @bitCast(f64, math.nan_u64),
             else => @compileError("snan not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
    diff --git a/std/math/pow.zig b/std/math/pow.zig
    index 85c3a71d56..55a2cd8c3e 100644
    --- a/std/math/pow.zig
    +++ b/std/math/pow.zig
    @@ -166,12 +166,12 @@ pub fn pow(comptime T: type, x: T, y: T) -> T {
             ae = -ae;
         }
     
    -    math.scalbn(a1, ae)
    +    return math.scalbn(a1, ae);
     }
     
     fn isOddInteger(x: f64) -> bool {
         const r = math.modf(x);
    -    r.fpart == 0.0 and i64(r.ipart) & 1 == 1
    +    return r.fpart == 0.0 and i64(r.ipart) & 1 == 1;
     }
     
     test "math.pow" {
    diff --git a/std/math/round.zig b/std/math/round.zig
    index a16bedc3f5..8e604d1b68 100644
    --- a/std/math/round.zig
    +++ b/std/math/round.zig
    @@ -10,11 +10,11 @@ const math = @import("index.zig");
     
     pub fn round(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(round32, x),
             f64 => @inlineCall(round64, x),
             else => @compileError("round not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn round32(x_: f32) -> f32 {
    @@ -48,9 +48,9 @@ fn round32(x_: f32) -> f32 {
         }
     
         if (u >> 31 != 0) {
    -        -y
    +        return -y;
         } else {
    -        y
    +        return y;
         }
     }
     
    @@ -85,9 +85,9 @@ fn round64(x_: f64) -> f64 {
         }
     
         if (u >> 63 != 0) {
    -        -y
    +        return -y;
         } else {
    -        y
    +        return y;
         }
     }
     
    diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig
    index 6e82194494..0c898a783c 100644
    --- a/std/math/scalbn.zig
    +++ b/std/math/scalbn.zig
    @@ -3,11 +3,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(scalbn32, x, n),
             f64 => @inlineCall(scalbn64, x, n),
             else => @compileError("scalbn not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn scalbn32(x: f32, n_: i32) -> f32 {
    @@ -37,7 +37,7 @@ fn scalbn32(x: f32, n_: i32) -> f32 {
         }
     
         const u = u32(n +% 0x7F) << 23;
    -    y * @bitCast(f32, u)
    +    return y * @bitCast(f32, u);
     }
     
     fn scalbn64(x: f64, n_: i32) -> f64 {
    @@ -67,7 +67,7 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
         }
     
         const u = u64(n +% 0x3FF) << 52;
    -    y * @bitCast(f64, u)
    +    return y * @bitCast(f64, u);
     }
     
     test "math.scalbn" {
    diff --git a/std/math/signbit.zig b/std/math/signbit.zig
    index 75b087f539..6efbc4db54 100644
    --- a/std/math/signbit.zig
    +++ b/std/math/signbit.zig
    @@ -3,21 +3,21 @@ const assert = @import("../debug.zig").assert;
     
     pub fn signbit(x: var) -> bool {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(signbit32, x),
             f64 => @inlineCall(signbit64, x),
             else => @compileError("signbit not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn signbit32(x: f32) -> bool {
         const bits = @bitCast(u32, x);
    -    bits >> 31 != 0
    +    return bits >> 31 != 0;
     }
     
     fn signbit64(x: f64) -> bool {
         const bits = @bitCast(u64, x);
    -    bits >> 63 != 0
    +    return bits >> 63 != 0;
     }
     
     test "math.signbit" {
    diff --git a/std/math/sin.zig b/std/math/sin.zig
    index 508bf5fae4..6fbbaff291 100644
    --- a/std/math/sin.zig
    +++ b/std/math/sin.zig
    @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn sin(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(sin32, x),
             f64 => @inlineCall(sin64, x),
             else => @compileError("sin not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // sin polynomial coefficients
    @@ -75,18 +75,18 @@ fn sin32(x_: f32) -> f32 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    const r = {
    +    const r = r: {
             if (j == 1 or j == 2) {
    -            1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
    +            break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
             } else {
    -            z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
    +            break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
             }
         };
     
         if (sign) {
    -        -r
    +        return -r;
         } else {
    -        r
    +        return r;
         }
     }
     
    @@ -127,25 +127,25 @@ fn sin64(x_: f64) -> f64 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    const r = {
    +    const r = r: {
             if (j == 1 or j == 2) {
    -            1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))))
    +            break :r 1.0 - 0.5 * w + w * w * (C5 + w * (C4 + w * (C3 + w * (C2 + w * (C1 + w * C0)))));
             } else {
    -            z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))))
    +            break :r z + z * w * (S5 + w * (S4 + w * (S3 + w * (S2 + w * (S1 + w * S0)))));
             }
         };
     
         if (sign) {
    -        -r
    +        return -r;
         } else {
    -        r
    +        return r;
         }
     }
     
     test "math.sin" {
         assert(sin(f32(0.0)) == sin32(0.0));
         assert(sin(f64(0.0)) == sin64(0.0));
    -    assert(comptime {math.sin(f64(2))} == math.sin(f64(2)));
    +    assert(comptime (math.sin(f64(2))) == math.sin(f64(2)));
     }
     
     test "math.sin32" {
    diff --git a/std/math/sinh.zig b/std/math/sinh.zig
    index 32f67a49a8..095dd7ea06 100644
    --- a/std/math/sinh.zig
    +++ b/std/math/sinh.zig
    @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
     
     pub fn sinh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(sinh32, x),
             f64 => @inlineCall(sinh64, x),
             else => @compileError("sinh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // sinh(x) = (exp(x) - 1 / exp(x)) / 2
    @@ -49,7 +49,7 @@ fn sinh32(x: f32) -> f32 {
         }
     
         // |x| > log(FLT_MAX) or nan
    -    2 * h * expo2(ax)
    +    return 2 * h * expo2(ax);
     }
     
     fn sinh64(x: f64) -> f64 {
    @@ -83,7 +83,7 @@ fn sinh64(x: f64) -> f64 {
         }
     
         // |x| > log(DBL_MAX) or nan
    -    2 * h * expo2(ax)
    +    return 2 * h * expo2(ax);
     }
     
     test "math.sinh" {
    diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig
    index 86426af3aa..263e616617 100644
    --- a/std/math/sqrt.zig
    +++ b/std/math/sqrt.zig
    @@ -14,7 +14,7 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @
         const T = @typeOf(x);
         switch (@typeId(T)) {
             TypeId.FloatLiteral => {
    -            return T(sqrt64(x))
    +            return T(sqrt64(x));
             },
             TypeId.Float => {
                 return switch (T) {
    @@ -64,7 +64,7 @@ fn sqrt32(x: f32) -> f32 {
             // subnormal
             var i: i32 = 0;
             while (ix & 0x00800000 == 0) : (i += 1) {
    -            ix <<= 1
    +            ix <<= 1;
             }
             m -= i - 1;
         }
    @@ -112,7 +112,7 @@ fn sqrt32(x: f32) -> f32 {
     
         ix = (q >> 1) + 0x3f000000;
         ix += m << 23;
    -    @bitCast(f32, ix)
    +    return @bitCast(f32, ix);
     }
     
     // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
    @@ -153,7 +153,7 @@ fn sqrt64(x: f64) -> f64 {
             // subnormal
             var i: u32 = 0;
             while (ix0 & 0x00100000 == 0) : (i += 1) {
    -            ix0 <<= 1
    +            ix0 <<= 1;
             }
             m -= i32(i) - 1;
             ix0 |= ix1 >> u5(32 - i);
    @@ -245,7 +245,7 @@ fn sqrt64(x: f64) -> f64 {
         iix0 = iix0 +% (m << 20);
     
         const uz = (u64(iix0) << 32) | ix1;
    -    @bitCast(f64, uz)
    +    return @bitCast(f64, uz);
     }
     
     test "math.sqrt" {
    diff --git a/std/math/tan.zig b/std/math/tan.zig
    index 6ac30fa667..2a3c46eb6f 100644
    --- a/std/math/tan.zig
    +++ b/std/math/tan.zig
    @@ -10,11 +10,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn tan(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(tan32, x),
             f64 => @inlineCall(tan64, x),
             else => @compileError("tan not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     const Tp0 = -1.30936939181383777646E4;
    @@ -62,11 +62,11 @@ fn tan32(x_: f32) -> f32 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    var r = {
    +    var r = r: {
             if (w > 1e-14) {
    -            z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4))
    +            break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4));
             } else {
    -            z
    +            break :r z;
             }
         };
     
    @@ -77,7 +77,7 @@ fn tan32(x_: f32) -> f32 {
             r = -r;
         }
     
    -    r
    +    return r;
     }
     
     fn tan64(x_: f64) -> f64 {
    @@ -111,11 +111,11 @@ fn tan64(x_: f64) -> f64 {
         const z = ((x - y * pi4a) - y * pi4b) - y * pi4c;
         const w = z * z;
     
    -    var r = {
    +    var r = r: {
             if (w > 1e-14) {
    -            z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4))
    +            break :r z + z * (w * ((Tp0 * w + Tp1) * w + Tp2) / ((((w + Tq1) * w + Tq2) * w + Tq3) * w + Tq4));
             } else {
    -            z
    +            break :r z;
             }
         };
     
    @@ -126,7 +126,7 @@ fn tan64(x_: f64) -> f64 {
             r = -r;
         }
     
    -    r
    +    return r;
     }
     
     test "math.tan" {
    diff --git a/std/math/tanh.zig b/std/math/tanh.zig
    index d9704f458a..c4fe8f2031 100644
    --- a/std/math/tanh.zig
    +++ b/std/math/tanh.zig
    @@ -11,11 +11,11 @@ const expo2 = @import("expo2.zig").expo2;
     
     pub fn tanh(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(tanh32, x),
             f64 => @inlineCall(tanh64, x),
             else => @compileError("tanh not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
    @@ -59,9 +59,9 @@ fn tanh32(x: f32) -> f32 {
         }
     
         if (u >> 31 != 0) {
    -        -t
    +        return -t;
         } else {
    -        t
    +        return t;
         }
     }
     
    @@ -104,9 +104,9 @@ fn tanh64(x: f64) -> f64 {
         }
     
         if (u >> 63 != 0) {
    -        -t
    +        return -t;
         } else {
    -        t
    +        return t;
         }
     }
     
    diff --git a/std/math/trunc.zig b/std/math/trunc.zig
    index 937a8155e6..01cb1bb84a 100644
    --- a/std/math/trunc.zig
    +++ b/std/math/trunc.zig
    @@ -9,11 +9,11 @@ const assert = @import("../debug.zig").assert;
     
     pub fn trunc(x: var) -> @typeOf(x) {
         const T = @typeOf(x);
    -    switch (T) {
    +    return switch (T) {
             f32 => @inlineCall(trunc32, x),
             f64 => @inlineCall(trunc64, x),
             else => @compileError("trunc not implemented for " ++ @typeName(T)),
    -    }
    +    };
     }
     
     fn trunc32(x: f32) -> f32 {
    @@ -30,10 +30,10 @@ fn trunc32(x: f32) -> f32 {
     
         m = u32(@maxValue(u32)) >> u5(e);
         if (u & m == 0) {
    -        x
    +        return x;
         } else {
             math.forceEval(x + 0x1p120);
    -        @bitCast(f32, u & ~m)
    +        return @bitCast(f32, u & ~m);
         }
     }
     
    @@ -51,10 +51,10 @@ fn trunc64(x: f64) -> f64 {
     
         m = u64(@maxValue(u64)) >> u6(e);
         if (u & m == 0) {
    -        x
    +        return x;
         } else {
             math.forceEval(x + 0x1p120);
    -        @bitCast(f64, u & ~m)
    +        return @bitCast(f64, u & ~m);
         }
     }
     
    diff --git a/std/mem.zig b/std/mem.zig
    index 4b3516b051..7438eba70a 100644
    --- a/std/mem.zig
    +++ b/std/mem.zig
    @@ -354,11 +354,11 @@ pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
     /// split("   abc def    ghi  ", " ")
     /// Will return slices for "abc", "def", "ghi", null, in that order.
     pub fn split(buffer: []const u8, split_bytes: []const u8) -> SplitIterator {
    -    SplitIterator {
    +    return SplitIterator {
             .index = 0,
             .buffer = buffer,
             .split_bytes = split_bytes,
    -    }
    +    };
     }
     
     test "mem.split" {
    @@ -552,7 +552,7 @@ test "std.mem.reverse" {
         var arr = []i32{ 5, 3, 1, 2, 4 };
         reverse(i32, arr[0..]);
     
    -    assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }))
    +    assert(eql(i32, arr, []i32{ 4, 2, 1, 3, 5 }));
     }
     
     /// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
    @@ -567,5 +567,5 @@ test "std.mem.rotate" {
         var arr = []i32{ 5, 3, 1, 2, 4 };
         rotate(i32, arr[0..], 2);
     
    -    assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }))
    +    assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
     }
    diff --git a/std/net.zig b/std/net.zig
    index 3551499c6b..a5fd4d6036 100644
    --- a/std/net.zig
    +++ b/std/net.zig
    @@ -72,7 +72,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
     //		if (family != AF_INET)
     //			buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
     //
    -        unreachable // TODO
    +        unreachable; // TODO
         }
     
         // TODO
    @@ -84,7 +84,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
         //    else => {},
         //};
     
    -    unreachable // TODO
    +    unreachable; // TODO
     }
     
     pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
    @@ -96,23 +96,23 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
         }
         const socket_fd = i32(socket_ret);
     
    -    const connect_ret = if (addr.family == linux.AF_INET) {
    +    const connect_ret = if (addr.family == linux.AF_INET) x: {
             var os_addr: linux.sockaddr_in = undefined;
             os_addr.family = addr.family;
             os_addr.port = endian.swapIfLe(u16, port);
             @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
             @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
    -        linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in))
    -    } else if (addr.family == linux.AF_INET6) {
    +        break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));
    +    } else if (addr.family == linux.AF_INET6) x: {
             var os_addr: linux.sockaddr_in6 = undefined;
             os_addr.family = addr.family;
             os_addr.port = endian.swapIfLe(u16, port);
             os_addr.flowinfo = 0;
             os_addr.scope_id = addr.scope_id;
             @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
    -        linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6))
    +        break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
         } else {
    -        unreachable
    +        unreachable;
         };
         const connect_err = linux.getErrno(connect_ret);
         if (connect_err > 0) {
    @@ -165,13 +165,13 @@ pub fn parseIpLiteral(buf: []const u8) -> %Address {
     fn hexDigit(c: u8) -> u8 {
         // TODO use switch with range
         if ('0' <= c and c <= '9') {
    -        c - '0'
    +        return c - '0';
         } else if ('A' <= c and c <= 'Z') {
    -        c - 'A' + 10
    +        return c - 'A' + 10;
         } else if ('a' <= c and c <= 'z') {
    -        c - 'a' + 10
    +        return c - 'a' + 10;
         } else {
    -        @maxValue(u8)
    +        return @maxValue(u8);
         }
     }
     
    diff --git a/std/os/child_process.zig b/std/os/child_process.zig
    index 5aa1578583..e719af65a8 100644
    --- a/std/os/child_process.zig
    +++ b/std/os/child_process.zig
    @@ -115,7 +115,7 @@ pub const ChildProcess = struct {
                 return self.spawnWindows();
             } else {
                 return self.spawnPosix();
    -        };
    +        }
         }
     
         pub fn spawnAndWait(self: &ChildProcess) -> %Term {
    @@ -249,12 +249,12 @@ pub const ChildProcess = struct {
         fn waitUnwrappedWindows(self: &ChildProcess) -> %void {
             const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
     
    -        self.term = (%Term)({
    +        self.term = (%Term)(x: {
                 var exit_code: windows.DWORD = undefined;
                 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
    -                Term { .Unknown = 0 }
    +                break :x Term { .Unknown = 0 };
                 } else {
    -                Term { .Exited = @bitCast(i32, exit_code)}
    +                break :x Term { .Exited = @bitCast(i32, exit_code)};
                 }
             });
     
    @@ -300,7 +300,7 @@ pub const ChildProcess = struct {
             defer {
                 os.close(self.err_pipe[0]);
                 os.close(self.err_pipe[1]);
    -        };
    +        }
     
             // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
             // waitpid, so this write is guaranteed to be after the child
    @@ -319,15 +319,15 @@ pub const ChildProcess = struct {
         }
     
         fn statusToTerm(status: i32) -> Term {
    -        return if (posix.WIFEXITED(status)) {
    +        return if (posix.WIFEXITED(status))
                 Term { .Exited = posix.WEXITSTATUS(status) }
    -        } else if (posix.WIFSIGNALED(status)) {
    +        else if (posix.WIFSIGNALED(status))
                 Term { .Signal = posix.WTERMSIG(status) }
    -        } else if (posix.WIFSTOPPED(status)) {
    +        else if (posix.WIFSTOPPED(status))
                 Term { .Stopped = posix.WSTOPSIG(status) }
    -        } else {
    +        else
                 Term { .Unknown = status }
    -        };
    +        ;
         }
     
         fn spawnPosix(self: &ChildProcess) -> %void {
    @@ -344,22 +344,22 @@ pub const ChildProcess = struct {
             %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
     
             const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
    -        const dev_null_fd = if (any_ignore) {
    +        const dev_null_fd = if (any_ignore)
                 %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
    -        } else {
    +        else
                 undefined
    -        };
    -        defer { if (any_ignore) os.close(dev_null_fd); };
    +        ;
    +        defer { if (any_ignore) os.close(dev_null_fd); }
     
             var env_map_owned: BufMap = undefined;
             var we_own_env_map: bool = undefined;
    -        const env_map = if (self.env_map) |env_map| {
    +        const env_map = if (self.env_map) |env_map| x: {
                 we_own_env_map = false;
    -            env_map
    -        } else {
    +            break :x env_map;
    +        } else x: {
                 we_own_env_map = true;
                 env_map_owned = %return os.getEnvMap(self.allocator);
    -            &env_map_owned
    +            break :x &env_map_owned;
             };
             defer { if (we_own_env_map) env_map_owned.deinit(); }
     
    @@ -450,13 +450,13 @@ pub const ChildProcess = struct {
                 self.stdout_behavior == StdIo.Ignore or
                 self.stderr_behavior == StdIo.Ignore);
     
    -        const nul_handle = if (any_ignore) {
    +        const nul_handle = if (any_ignore)
                 %return os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
                     windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null)
    -        } else {
    +        else
                 undefined
    -        };
    -        defer { if (any_ignore) os.close(nul_handle); };
    +        ;
    +        defer { if (any_ignore) os.close(nul_handle); }
             if (any_ignore) {
                 %return windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
             }
    @@ -542,30 +542,30 @@ pub const ChildProcess = struct {
             };
             var piProcInfo: windows.PROCESS_INFORMATION = undefined;
     
    -        const cwd_slice = if (self.cwd) |cwd| {
    +        const cwd_slice = if (self.cwd) |cwd|
                 %return cstr.addNullByte(self.allocator, cwd)
    -        } else {
    +        else
                 null
    -        };
    +        ;
             defer if (cwd_slice) |cwd| self.allocator.free(cwd);
             const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
     
    -        const maybe_envp_buf = if (self.env_map) |env_map| {
    +        const maybe_envp_buf = if (self.env_map) |env_map|
                 %return os.createWindowsEnvBlock(self.allocator, env_map)
    -        } else {
    +        else
                 null
    -        };
    +        ;
             defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
             const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
     
             // the cwd set in ChildProcess is in effect when choosing the executable path
             // to match posix semantics
    -        const app_name = if (self.cwd) |cwd| {
    +        const app_name = if (self.cwd) |cwd| x: {
                 const resolved = %return os.path.resolve(self.allocator, cwd, self.argv[0]);
                 defer self.allocator.free(resolved);
    -            %return cstr.addNullByte(self.allocator, resolved)
    -        } else {
    -            %return cstr.addNullByte(self.allocator, self.argv[0])
    +            break :x %return cstr.addNullByte(self.allocator, resolved);
    +        } else x: {
    +            break :x %return cstr.addNullByte(self.allocator, self.argv[0]);
             };
             defer self.allocator.free(app_name);
     
    @@ -741,7 +741,7 @@ fn makePipe() -> %[2]i32 {
             return switch (err) {
                 posix.EMFILE, posix.ENFILE => error.SystemResources,
                 else => os.unexpectedErrorPosix(err),
    -        }
    +        };
         }
         return fds;
     }
    @@ -800,10 +800,10 @@ fn handleTerm(pid: i32, status: i32) {
         }
     }
     
    -const sigchld_set = {
    +const sigchld_set = x: {
         var signal_set = posix.empty_sigset;
         posix.sigaddset(&signal_set, posix.SIGCHLD);
    -    signal_set
    +    break :x signal_set;
     };
     
     fn block_SIGCHLD() {
    diff --git a/std/os/darwin.zig b/std/os/darwin.zig
    index 9d80c64006..f4166c2151 100644
    --- a/std/os/darwin.zig
    +++ b/std/os/darwin.zig
    @@ -97,63 +97,63 @@ pub const SIGINFO   = 29; /// information request
     pub const SIGUSR1   = 30; /// user defined signal 1
     pub const SIGUSR2   = 31; /// user defined signal 2
     
    -fn wstatus(x: i32) -> i32 { x & 0o177 }
    +fn wstatus(x: i32) -> i32 { return x & 0o177; }
     const wstopped = 0o177;
    -pub fn WEXITSTATUS(x: i32) -> i32 { x >> 8 }
    -pub fn WTERMSIG(x: i32) -> i32 { wstatus(x) }
    -pub fn WSTOPSIG(x: i32) -> i32 { x >> 8 }
    -pub fn WIFEXITED(x: i32) -> bool { wstatus(x) == 0 }
    -pub fn WIFSTOPPED(x: i32) -> bool { wstatus(x) == wstopped and WSTOPSIG(x) != 0x13 }
    -pub fn WIFSIGNALED(x: i32) -> bool { wstatus(x) != wstopped and wstatus(x) != 0 }
    +pub fn WEXITSTATUS(x: i32) -> i32 { return x >> 8; }
    +pub fn WTERMSIG(x: i32) -> i32 { return wstatus(x); }
    +pub fn WSTOPSIG(x: i32) -> i32 { return x >> 8; }
    +pub fn WIFEXITED(x: i32) -> bool { return wstatus(x) == 0; }
    +pub fn WIFSTOPPED(x: i32) -> bool { return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; }
    +pub fn WIFSIGNALED(x: i32) -> bool { return wstatus(x) != wstopped and wstatus(x) != 0; }
     
     /// Get the errno from a syscall return value, or 0 for no error.
     pub fn getErrno(r: usize) -> usize {
         const signed_r = @bitCast(isize, r);
    -    if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
    +    return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
     }
     
     pub fn close(fd: i32) -> usize {
    -    errnoWrap(c.close(fd))
    +    return errnoWrap(c.close(fd));
     }
     
     pub fn abort() -> noreturn {
    -    c.abort()
    +    return c.abort();
     }
     
     pub fn exit(code: i32) -> noreturn {
    -    c.exit(code)
    +    return c.exit(code);
     }
     
     pub fn isatty(fd: i32) -> bool {
    -    c.isatty(fd) != 0
    +    return c.isatty(fd) != 0;
     }
     
     pub fn fstat(fd: i32, buf: &c.Stat) -> usize {
    -    errnoWrap(c.@"fstat$INODE64"(fd, buf))
    +    return errnoWrap(c.@"fstat$INODE64"(fd, buf));
     }
     
     pub fn lseek(fd: i32, offset: isize, whence: c_int) -> usize {
    -    errnoWrap(c.lseek(fd, offset, whence))
    +    return errnoWrap(c.lseek(fd, offset, whence));
     }
     
     pub fn open(path: &const u8, flags: u32, mode: usize) -> usize {
    -    errnoWrap(c.open(path, @bitCast(c_int, flags), mode))
    +    return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
     }
     
     pub fn raise(sig: i32) -> usize {
    -    errnoWrap(c.raise(sig))
    +    return errnoWrap(c.raise(sig));
     }
     
     pub fn read(fd: i32, buf: &u8, nbyte: usize) -> usize {
    -    errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte))
    +    return errnoWrap(c.read(fd, @ptrCast(&c_void, buf), nbyte));
     }
     
     pub fn stat(noalias path: &const u8, noalias buf: &stat) -> usize {
    -    errnoWrap(c.stat(path, buf))
    +    return errnoWrap(c.stat(path, buf));
     }
     
     pub fn write(fd: i32, buf: &const u8, nbyte: usize) -> usize {
    -    errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte))
    +    return errnoWrap(c.write(fd, @ptrCast(&const c_void, buf), nbyte));
     }
     
     pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
    @@ -166,79 +166,79 @@ pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32,
     }
     
     pub fn munmap(address: &u8, length: usize) -> usize {
    -    errnoWrap(c.munmap(@ptrCast(&c_void, address), length))
    +    return errnoWrap(c.munmap(@ptrCast(&c_void, address), length));
     }
     
     pub fn unlink(path: &const u8) -> usize {
    -    errnoWrap(c.unlink(path))
    +    return errnoWrap(c.unlink(path));
     }
     
     pub fn getcwd(buf: &u8, size: usize) -> usize {
    -    if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0
    +    return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(*c._errno())) else 0;
     }
     
     pub fn waitpid(pid: i32, status: &i32, options: u32) -> usize {
         comptime assert(i32.bit_count == c_int.bit_count);
    -    errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options)))
    +    return errnoWrap(c.waitpid(pid, @ptrCast(&c_int, status), @bitCast(c_int, options)));
     }
     
     pub fn fork() -> usize {
    -    errnoWrap(c.fork())
    +    return errnoWrap(c.fork());
     }
     
     pub fn pipe(fds: &[2]i32) -> usize {
         comptime assert(i32.bit_count == c_int.bit_count);
    -    errnoWrap(c.pipe(@ptrCast(&c_int, fds)))
    +    return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
     }
     
     pub fn mkdir(path: &const u8, mode: u32) -> usize {
    -    errnoWrap(c.mkdir(path, mode))
    +    return errnoWrap(c.mkdir(path, mode));
     }
     
     pub fn symlink(existing: &const u8, new: &const u8) -> usize {
    -    errnoWrap(c.symlink(existing, new))
    +    return errnoWrap(c.symlink(existing, new));
     }
     
     pub fn rename(old: &const u8, new: &const u8) -> usize {
    -    errnoWrap(c.rename(old, new))
    +    return errnoWrap(c.rename(old, new));
     }
     
     pub fn chdir(path: &const u8) -> usize {
    -    errnoWrap(c.chdir(path))
    +    return errnoWrap(c.chdir(path));
     }
     
     pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8)
         -> usize
     {
    -    errnoWrap(c.execve(path, argv, envp))
    +    return errnoWrap(c.execve(path, argv, envp));
     }
     
     pub fn dup2(old: i32, new: i32) -> usize {
    -    errnoWrap(c.dup2(old, new))
    +    return errnoWrap(c.dup2(old, new));
     }
     
     pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
    -    errnoWrap(c.readlink(path, buf_ptr, buf_len))
    +    return errnoWrap(c.readlink(path, buf_ptr, buf_len));
     }
     
     pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
    -    errnoWrap(c.nanosleep(req, rem))
    +    return errnoWrap(c.nanosleep(req, rem));
     }
     
     pub fn realpath(noalias filename: &const u8, noalias resolved_name: &u8) -> usize {
    -    if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0
    +    return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(*c._errno())) else 0;
     }
     
     pub fn setreuid(ruid: u32, euid: u32) -> usize {
    -    errnoWrap(c.setreuid(ruid, euid))
    +    return errnoWrap(c.setreuid(ruid, euid));
     }
     
     pub fn setregid(rgid: u32, egid: u32) -> usize {
    -    errnoWrap(c.setregid(rgid, egid))
    +    return errnoWrap(c.setregid(rgid, egid));
     }
     
     pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
    -    errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset))
    +    return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset));
     }
     
     pub fn sigaction(sig: u5, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
    @@ -285,9 +285,5 @@ pub fn sigaddset(set: &sigset_t, signo: u5) {
     /// that the kernel represents it to libc. Errno was a mistake, let's make
     /// it go away forever.
     fn errnoWrap(value: isize) -> usize {
    -    @bitCast(usize, if (value == -1) {
    -        -isize(*c._errno())
    -    } else {
    -        value
    -    })
    +    return @bitCast(usize, if (value == -1) -isize(*c._errno()) else value);
     }
    diff --git a/std/os/index.zig b/std/os/index.zig
    index 3eba15ef8a..09109c3242 100644
    --- a/std/os/index.zig
    +++ b/std/os/index.zig
    @@ -84,7 +84,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
                         posix.EFAULT => unreachable,
                         posix.EINTR  => continue,
                         else         => unexpectedErrorPosix(err),
    -                }
    +                };
                 }
                 return;
             },
    @@ -151,18 +151,17 @@ pub coldcc fn exit(status: i32) -> noreturn {
         }
         switch (builtin.os) {
             Os.linux, Os.darwin, Os.macosx, Os.ios => {
    -            posix.exit(status)
    +            posix.exit(status);
             },
             Os.windows => {
                 // Map a possibly negative status code to a non-negative status for the systems default
                 // integer width.
    -            const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) {
    +            const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
                     @truncate(c_uint, @bitCast(u32, status))
    -            } else {
    -                c_uint(@bitCast(u32, status))
    -            };
    +            else
    +                c_uint(@bitCast(u32, status));
     
    -            windows.ExitProcess(p_status)
    +            windows.ExitProcess(p_status);
             },
             else => @compileError("Unsupported OS"),
         }
    @@ -289,7 +288,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
                     posix.EPERM => error.AccessDenied,
                     posix.EEXIST => error.PathAlreadyExists,
                     else => unexpectedErrorPosix(err),
    -            }
    +            };
             }
             return i32(result);
         }
    @@ -680,7 +679,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) -> %void
                 windows.ERROR.ACCESS_DENIED => error.AccessDenied,
                 windows.ERROR.FILENAME_EXCED_RANGE, windows.ERROR.INVALID_PARAMETER => error.NameTooLong,
                 else => unexpectedErrorWindows(err),
    -        }
    +        };
         }
     }
     
    @@ -1006,7 +1005,7 @@ pub const Dir = struct {
                                     continue;
                                 },
                                 else => return unexpectedErrorPosix(err),
    -                        };
    +                        }
                         }
                         if (result == 0)
                             return null;
    diff --git a/std/os/linux.zig b/std/os/linux.zig
    index 4ba4db603f..f9baa43098 100644
    --- a/std/os/linux.zig
    +++ b/std/os/linux.zig
    @@ -367,14 +367,14 @@ pub const TFD_CLOEXEC = O_CLOEXEC;
     pub const TFD_TIMER_ABSTIME = 1;
     pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
     
    -fn unsigned(s: i32) -> u32 { @bitCast(u32, s) }
    -fn signed(s: u32) -> i32 { @bitCast(i32, s) }
    -pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
    -pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) }
    -pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) }
    -pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 }
    -pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 }
    -pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff }
    +fn unsigned(s: i32) -> u32 { return @bitCast(u32, s); }
    +fn signed(s: u32) -> i32 { return @bitCast(i32, s); }
    +pub fn WEXITSTATUS(s: i32) -> i32 { return signed((unsigned(s) & 0xff00) >> 8); }
    +pub fn WTERMSIG(s: i32) -> i32 { return signed(unsigned(s) & 0x7f); }
    +pub fn WSTOPSIG(s: i32) -> i32 { return WEXITSTATUS(s); }
    +pub fn WIFEXITED(s: i32) -> bool { return WTERMSIG(s) == 0; }
    +pub fn WIFSTOPPED(s: i32) -> bool { return (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00; }
    +pub fn WIFSIGNALED(s: i32) -> bool { return (unsigned(s)&0xffff)-%1 < 0xff; }
     
     
     pub const winsize = extern struct {
    @@ -387,31 +387,31 @@ pub const winsize = extern struct {
     /// Get the errno from a syscall return value, or 0 for no error.
     pub fn getErrno(r: usize) -> usize {
         const signed_r = @bitCast(isize, r);
    -    if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
    +    return if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0;
     }
     
     pub fn dup2(old: i32, new: i32) -> usize {
    -    arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
    +    return arch.syscall2(arch.SYS_dup2, usize(old), usize(new));
     }
     
     pub fn chdir(path: &const u8) -> usize {
    -    arch.syscall1(arch.SYS_chdir, @ptrToInt(path))
    +    return arch.syscall1(arch.SYS_chdir, @ptrToInt(path));
     }
     
     pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
    -    arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp))
    +    return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
     }
     
     pub fn fork() -> usize {
    -    arch.syscall0(arch.SYS_fork)
    +    return arch.syscall0(arch.SYS_fork);
     }
     
     pub fn getcwd(buf: &u8, size: usize) -> usize {
    -    arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size)
    +    return arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size);
     }
     
     pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {
    -    arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count)
    +    return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count);
     }
     
     pub fn isatty(fd: i32) -> bool {
    @@ -420,123 +420,123 @@ pub fn isatty(fd: i32) -> bool {
     }
     
     pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
    -    arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len)
    +    return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
     }
     
     pub fn mkdir(path: &const u8, mode: u32) -> usize {
    -    arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode)
    +    return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode);
     }
     
     pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize)
         -> usize
     {
    -    arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
    -        @bitCast(usize, offset))
    +    return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd),
    +        @bitCast(usize, offset));
     }
     
     pub fn munmap(address: &u8, length: usize) -> usize {
    -    arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length)
    +    return arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length);
     }
     
     pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
    -    arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count)
    +    return arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count);
     }
     
     pub fn rmdir(path: &const u8) -> usize {
    -    arch.syscall1(arch.SYS_rmdir, @ptrToInt(path))
    +    return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path));
     }
     
     pub fn symlink(existing: &const u8, new: &const u8) -> usize {
    -    arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new))
    +    return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
     }
     
     pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
    -    arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset)
    +    return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset);
     }
     
     pub fn pipe(fd: &[2]i32) -> usize {
    -    pipe2(fd, 0)
    +    return pipe2(fd, 0);
     }
     
     pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {
    -    arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags)
    +    return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags);
     }
     
     pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
    -    arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count)
    +    return arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count);
     }
     
     pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
    -    arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset)
    +    return arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset);
     }
     
     pub fn rename(old: &const u8, new: &const u8) -> usize {
    -    arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new))
    +    return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new));
     }
     
     pub fn open(path: &const u8, flags: u32, perm: usize) -> usize {
    -    arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm)
    +    return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm);
     }
     
     pub fn create(path: &const u8, perm: usize) -> usize {
    -    arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm)
    +    return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm);
     }
     
     pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
    -    arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode)
    +    return arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode);
     }
     
     pub fn close(fd: i32) -> usize {
    -    arch.syscall1(arch.SYS_close, usize(fd))
    +    return arch.syscall1(arch.SYS_close, usize(fd));
     }
     
     pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize {
    -    arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos)
    +    return arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos);
     }
     
     pub fn exit(status: i32) -> noreturn {
         _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status)));
    -    unreachable
    +    unreachable;
     }
     
     pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
    -    arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags))
    +    return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags));
     }
     
     pub fn kill(pid: i32, sig: i32) -> usize {
    -    arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig))
    +    return arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig));
     }
     
     pub fn unlink(path: &const u8) -> usize {
    -    arch.syscall1(arch.SYS_unlink, @ptrToInt(path))
    +    return arch.syscall1(arch.SYS_unlink, @ptrToInt(path));
     }
     
     pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
    -    arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0)
    +    return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
     }
     
     pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
    -    arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem))
    +    return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
     }
     
     pub fn setuid(uid: u32) -> usize {
    -    arch.syscall1(arch.SYS_setuid, uid)
    +    return arch.syscall1(arch.SYS_setuid, uid);
     }
     
     pub fn setgid(gid: u32) -> usize {
    -    arch.syscall1(arch.SYS_setgid, gid)
    +    return arch.syscall1(arch.SYS_setgid, gid);
     }
     
     pub fn setreuid(ruid: u32, euid: u32) -> usize {
    -    arch.syscall2(arch.SYS_setreuid, ruid, euid)
    +    return arch.syscall2(arch.SYS_setreuid, ruid, euid);
     }
     
     pub fn setregid(rgid: u32, egid: u32) -> usize {
    -    arch.syscall2(arch.SYS_setregid, rgid, egid)
    +    return arch.syscall2(arch.SYS_setregid, rgid, egid);
     }
     
     pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
    -    arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8)
    +    return arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8);
     }
     
     pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize {
    @@ -652,69 +652,69 @@ pub const iovec = extern struct {
     };
     
     pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
    -    arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len))
    +    return arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len));
     }
     
     pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
    -    arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len))
    +    return arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
     }
     
     pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {
    -    arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol))
    +    return arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol));
     }
     
     pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize {
    -    arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen))
    +    return arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));
     }
     
     pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize {
    -    arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen))
    +    return arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));
     }
     
     pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize {
    -    arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags)
    +    return arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags);
     }
     
     pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
    -    arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len))
    +    return arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len));
     }
     
     pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize {
    -    arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags)
    +    return arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags);
     }
     
     pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
         noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize
     {
    -    arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen))
    +    return arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
     }
     
     pub fn shutdown(fd: i32, how: i32) -> usize {
    -    arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how))
    +    return arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how));
     }
     
     pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
    -    arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len))
    +    return arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
     }
     
     pub fn listen(fd: i32, backlog: i32) -> usize {
    -    arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog))
    +    return arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog));
     }
     
     pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize {
    -    arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen))
    +    return arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen));
     }
     
     pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize {
    -    arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]))
    +    return arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]));
     }
     
     pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
    -    accept4(fd, addr, len, 0)
    +    return accept4(fd, addr, len, 0);
     }
     
     pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize {
    -    arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags)
    +    return arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
     }
     
     // error NameTooLong;
    @@ -749,7 +749,7 @@ pub const Stat = arch.Stat;
     pub const timespec = arch.timespec;
     
     pub fn fstat(fd: i32, stat_buf: &Stat) -> usize {
    -    arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf))
    +    return arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf));
     }
     
     pub const epoll_data = u64;
    @@ -760,19 +760,19 @@ pub const epoll_event = extern struct {
     };
     
     pub fn epoll_create() -> usize {
    -    arch.syscall1(arch.SYS_epoll_create, usize(1))
    +    return arch.syscall1(arch.SYS_epoll_create, usize(1));
     }
     
     pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) -> usize {
    -    arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev))
    +    return arch.syscall4(arch.SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
     }
     
     pub fn epoll_wait(epoll_fd: i32, events: &epoll_event, maxevents: i32, timeout: i32) -> usize {
    -    arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout))
    +    return arch.syscall4(arch.SYS_epoll_wait, usize(epoll_fd), @ptrToInt(events), usize(maxevents), usize(timeout));
     }
     
     pub fn timerfd_create(clockid: i32, flags: u32) -> usize {
    -    arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags))
    +    return arch.syscall2(arch.SYS_timerfd_create, usize(clockid), usize(flags));
     }
     
     pub const itimerspec = extern struct {
    @@ -781,11 +781,11 @@ pub const itimerspec = extern struct {
     };
     
     pub fn timerfd_gettime(fd: i32, curr_value: &itimerspec) -> usize {
    -    arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value))
    +    return arch.syscall2(arch.SYS_timerfd_gettime, usize(fd), @ptrToInt(curr_value));
     }
     
     pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_value: ?&itimerspec) -> usize {
    -    arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value))
    +    return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
     }
     
     test "import linux_test" {
    diff --git a/std/os/linux_x86_64.zig b/std/os/linux_x86_64.zig
    index 6c94528df0..db78decde2 100644
    --- a/std/os/linux_x86_64.zig
    +++ b/std/os/linux_x86_64.zig
    @@ -371,52 +371,52 @@ pub const F_GETOWN_EX = 16;
     pub const F_GETOWNER_UIDS = 17;
     
     pub fn syscall0(number: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall1(number: usize, arg1: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1),
                 [arg2] "{rsi}" (arg2)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1),
                 [arg2] "{rsi}" (arg2),
                 [arg3] "{rdx}" (arg3)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1),
                 [arg2] "{rsi}" (arg2),
                 [arg3] "{rdx}" (arg3),
                 [arg4] "{r10}" (arg4)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1),
    @@ -424,13 +424,13 @@ pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
                 [arg3] "{rdx}" (arg3),
                 [arg4] "{r10}" (arg4),
                 [arg5] "{r8}" (arg5)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
         arg5: usize, arg6: usize) -> usize
     {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             : [ret] "={rax}" (-> usize)
             : [number] "{rax}" (number),
                 [arg1] "{rdi}" (arg1),
    @@ -439,14 +439,14 @@ pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usiz
                 [arg4] "{r10}" (arg4),
                 [arg5] "{r8}" (arg5),
                 [arg6] "{r9}" (arg6)
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     pub nakedcc fn restore_rt() {
    -    asm volatile ("syscall"
    +    return asm volatile ("syscall"
             :
             : [number] "{rax}" (usize(SYS_rt_sigreturn))
    -        : "rcx", "r11")
    +        : "rcx", "r11");
     }
     
     
    diff --git a/std/os/path.zig b/std/os/path.zig
    index 3fd7b5e2db..a42ebb3433 100644
    --- a/std/os/path.zig
    +++ b/std/os/path.zig
    @@ -749,21 +749,19 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
         const resolved_to = %return resolveWindows(allocator, [][]const u8{to});
         defer if (clean_up_resolved_to) allocator.free(resolved_to);
     
    -    const result_is_to = if (drive(resolved_to)) |to_drive| {
    -        if (drive(resolved_from)) |from_drive| {
    +    const result_is_to = if (drive(resolved_to)) |to_drive|
    +        if (drive(resolved_from)) |from_drive|
                 asciiUpper(from_drive[0]) != asciiUpper(to_drive[0])
    -        } else {
    +        else
                 true
    -        }
    -    } else if (networkShare(resolved_to)) |to_ns| {
    -        if (networkShare(resolved_from)) |from_ns| {
    +    else if (networkShare(resolved_to)) |to_ns|
    +        if (networkShare(resolved_from)) |from_ns|
                 !networkShareServersEql(to_ns, from_ns)
    -        } else {
    +        else
                 true
    -        }
    -    } else {
    -        unreachable
    -    };
    +    else
    +        unreachable;
    +
         if (result_is_to) {
             clean_up_resolved_to = false;
             return resolved_to;
    @@ -964,14 +962,16 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
     
                     // windows returns \\?\ prepended to the path
                     // we strip it because nobody wants \\?\ prepended to their path
    -                const final_len = if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
    -                    var i: usize = 4;
    -                    while (i < result) : (i += 1) {
    -                        buf[i - 4] = buf[i];
    +                const final_len = x: {
    +                    if (result > 4 and mem.startsWith(u8, buf, "\\\\?\\")) {
    +                        var i: usize = 4;
    +                        while (i < result) : (i += 1) {
    +                            buf[i - 4] = buf[i];
    +                        }
    +                        break :x result - 4;
    +                    } else {
    +                        break :x result;
                         }
    -                    result - 4
    -                } else {
    -                    result
                     };
     
                     return allocator.shrink(u8, buf, final_len);
    diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
    index b3fc095d43..0964adc16b 100644
    --- a/std/os/windows/util.zig
    +++ b/std/os/windows/util.zig
    @@ -122,7 +122,7 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
     /// Caller must free result.
     pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
         // count bytes needed
    -    const bytes_needed = {
    +    const bytes_needed = x: {
             var bytes_needed: usize = 1; // 1 for the final null byte
             var it = env_map.iterator();
             while (it.next()) |pair| {
    @@ -130,7 +130,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
                 // +1 for null byte
                 bytes_needed += pair.key.len + pair.value.len + 2;
             }
    -        bytes_needed
    +        break :x bytes_needed;
         };
         const result = %return allocator.alloc(u8, bytes_needed);
         %defer allocator.free(result);
    diff --git a/std/rand.zig b/std/rand.zig
    index 09e0c8ac78..73801a078f 100644
    --- a/std/rand.zig
    +++ b/std/rand.zig
    @@ -28,9 +28,9 @@ pub const Rand = struct {
     
         /// Initialize random state with the given seed.
         pub fn init(seed: usize) -> Rand {
    -        Rand {
    +        return Rand {
                 .rng = Rng.init(seed),
    -        }
    +        };
         }
     
         /// Get an integer or boolean with random bits.
    @@ -78,13 +78,13 @@ pub const Rand = struct {
                     const end_uint = uint(end);
                     const total_range = math.absCast(start) + end_uint;
                     const value = r.range(uint, 0, total_range);
    -                const result = if (value < end_uint) {
    -                    T(value)
    -                } else if (value == end_uint) {
    -                    start
    -                } else {
    +                const result = if (value < end_uint) x: {
    +                    break :x T(value);
    +                } else if (value == end_uint) x: {
    +                    break :x start;
    +                } else x: {
                         // Can't overflow because the range is over signed ints
    -                    %%math.negateCast(value - end_uint)
    +                    break :x %%math.negateCast(value - end_uint);
                     };
                     return result;
                 } else {
    @@ -114,13 +114,13 @@ pub const Rand = struct {
             // const rand_bits = r.rng.scalar(int) & mask;
             // return @float_compose(T, false, 0, rand_bits) - 1.0
             const int_type = @IntType(false, @sizeOf(T) * 8);
    -        const precision = if (T == f32) {
    +        const precision = if (T == f32)
                 16777216
    -        } else if (T == f64) {
    +        else if (T == f64)
                 9007199254740992
    -        } else {
    +        else
                 @compileError("unknown floating point type")
    -        };
    +        ;
             return T(r.range(int_type, 0, precision)) / T(precision);
         }
     };
    @@ -133,7 +133,7 @@ fn MersenneTwister(
         comptime t: math.Log2Int(int), comptime c: int,
         comptime l: math.Log2Int(int), comptime f: int) -> type
     {
    -    struct {
    +    return struct {
             const Self = this;
     
             array: [n]int,
    @@ -189,7 +189,7 @@ fn MersenneTwister(
     
                 return x;
             }
    -    }
    +    };
     }
     
     test "rand float 32" {
    diff --git a/std/sort.zig b/std/sort.zig
    index c6b1500b8e..a36a5e1747 100644
    --- a/std/sort.zig
    +++ b/std/sort.zig
    @@ -355,7 +355,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
                     // these values will be pulled out to the start of A
                     last = A.start;
                     count = 1;
    -                while (count < find) : ({last = index; count += 1}) {
    +                while (count < find) : ({last = index; count += 1;}) {
                         index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count);
                         if (index == A.end) break;
                     }
    @@ -410,7 +410,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
                     // these values will be pulled out to the end of B
                     last = B.end - 1;
                     count = 1;
    -                while (count < find) : ({last = index - 1; count += 1}) {
    +                while (count < find) : ({last = index - 1; count += 1;}) {
                         index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count);
                         if (index == B.start) break;
                     }
    @@ -547,7 +547,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
                         // swap the first value of each A block with the value in buffer1
                         var indexA = buffer1.start;
                         index = firstA.end;
    -                    while (index < blockA.end) : ({indexA += 1; index += block_size}) {
    +                    while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
                             mem.swap(T, &items[indexA], &items[index]);
                         }
                         
    @@ -1093,7 +1093,7 @@ test "another sort case" {
         var arr = []i32{ 5, 3, 1, 2, 4 };
         sort(i32, arr[0..], i32asc);
     
    -    assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }))
    +    assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 }));
     }
     
     test "sort fuzz testing" {
    diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig
    index 430eeb395e..e54d85e6ef 100644
    --- a/std/special/build_runner.zig
    +++ b/std/special/build_runner.zig
    @@ -45,21 +45,17 @@ pub fn main() -> %void {
     
         var stderr_file = io.getStdErr();
         var stderr_file_stream: io.FileOutStream = undefined;
    -    var stderr_stream: %&io.OutStream = if (stderr_file) |*f| {
    +    var stderr_stream: %&io.OutStream = if (stderr_file) |*f| x: {
             stderr_file_stream = io.FileOutStream.init(f);
    -        &stderr_file_stream.stream
    -    } else |err| {
    -        err
    -    };
    +        break :x &stderr_file_stream.stream;
    +    } else |err| err;
     
         var stdout_file = io.getStdOut();
         var stdout_file_stream: io.FileOutStream = undefined;
    -    var stdout_stream: %&io.OutStream = if (stdout_file) |*f| {
    +    var stdout_stream: %&io.OutStream = if (stdout_file) |*f| x: {
             stdout_file_stream = io.FileOutStream.init(f);
    -        &stdout_file_stream.stream
    -    } else |err| {
    -        err
    -    };
    +        break :x &stdout_file_stream.stream;
    +    } else |err| err;
     
         while (arg_it.next(allocator)) |err_or_arg| {
             const arg = %return unwrapArg(err_or_arg);
    diff --git a/std/special/builtin.zig b/std/special/builtin.zig
    index a2455a9690..e6c09863ca 100644
    --- a/std/special/builtin.zig
    +++ b/std/special/builtin.zig
    @@ -46,15 +46,15 @@ extern fn __stack_chk_fail() -> noreturn {
     
     const math = @import("../math/index.zig");
     
    -export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) }
    -export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) }
    +export fn fmodf(x: f32, y: f32) -> f32 { return generic_fmod(f32, x, y); }
    +export fn fmod(x: f64, y: f64) -> f64 { return generic_fmod(f64, x, y); }
     
     // TODO add intrinsics for these (and probably the double version too)
     // and have the math stuff use the intrinsic. same as @mod and @rem
    -export fn floorf(x: f32) -> f32 { math.floor(x) }
    -export fn ceilf(x: f32) -> f32 { math.ceil(x) }
    -export fn floor(x: f64) -> f64 { math.floor(x) }
    -export fn ceil(x: f64) -> f64 { math.ceil(x) }
    +export fn floorf(x: f32) -> f32 { return math.floor(x); }
    +export fn ceilf(x: f32) -> f32 { return math.ceil(x); }
    +export fn floor(x: f64) -> f64 { return math.floor(x); }
    +export fn ceil(x: f64) -> f64 { return math.ceil(x); }
     
     fn generic_fmod(comptime T: type, x: T, y: T) -> T {
         @setDebugSafety(this, false);
    @@ -84,7 +84,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
         // normalize x and y
         if (ex == 0) {
             i = ux << exp_bits;
    -        while (i >> bits_minus_1 == 0) : ({ex -= 1; i <<= 1}) {}
    +        while (i >> bits_minus_1 == 0) : (b: {ex -= 1; break :b i <<= 1;}) {}
             ux <<= log2uint(@bitCast(u32, -ex + 1));
         } else {
             ux &= @maxValue(uint) >> exp_bits;
    @@ -92,7 +92,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
         }
         if (ey == 0) {
             i = uy << exp_bits;
    -        while (i >> bits_minus_1 == 0) : ({ey -= 1; i <<= 1}) {}
    +        while (i >> bits_minus_1 == 0) : (b: {ey -= 1; break :b i <<= 1;}) {}
             uy <<= log2uint(@bitCast(u32, -ey + 1));
         } else {
             uy &= @maxValue(uint) >> exp_bits;
    @@ -115,7 +115,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) -> T {
                 return 0 * x;
             ux = i;
         }
    -    while (ux >> digits == 0) : ({ux <<= 1; ex -= 1}) {}
    +    while (ux >> digits == 0) : (b: {ux <<= 1; break :b ex -= 1;}) {}
     
         // scale result up
         if (ex > 0) {
    diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig
    index 0834072672..b88c35019b 100644
    --- a/std/special/compiler_rt/comparetf2.zig
    +++ b/std/special/compiler_rt/comparetf2.zig
    @@ -38,27 +38,25 @@ pub extern fn __letf2(a: f128, b: f128) -> c_int {
     
         // If at least one of a and b is positive, we get the same result comparing
         // a and b as signed integers as we would with a floating-point compare.
    -    return if ((aInt & bInt) >= 0) {
    -        if (aInt < bInt) {
    +    return if ((aInt & bInt) >= 0)
    +        if (aInt < bInt)
                 LE_LESS
    -        } else if (aInt == bInt) {
    +        else if (aInt == bInt)
                 LE_EQUAL
    -        } else {
    +        else
                 LE_GREATER
    -        }
    -    } else {
    +    else
             // Otherwise, both are negative, so we need to flip the sense of the
             // comparison to get the correct result.  (This assumes a twos- or ones-
             // complement integer representation; if integers are represented in a
             // sign-magnitude representation, then this flip is incorrect).
    -        if (aInt > bInt) {
    +        if (aInt > bInt)
                 LE_LESS
    -        } else if (aInt == bInt) {
    +        else if (aInt == bInt)
                 LE_EQUAL
    -        } else {
    +        else
                 LE_GREATER
    -        }
    -    };
    +    ;
     }
     
     // TODO https://github.com/zig-lang/zig/issues/305
    @@ -78,23 +76,21 @@ pub extern fn __getf2(a: f128, b: f128) -> c_int {
     
         if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
         if ((aAbs | bAbs) == 0) return GE_EQUAL;
    -    return if ((aInt & bInt) >= 0) {
    -        if (aInt < bInt) {
    +    return if ((aInt & bInt) >= 0)
    +        if (aInt < bInt)
                 GE_LESS
    -        } else if (aInt == bInt) {
    +        else if (aInt == bInt)
                 GE_EQUAL
    -        } else {
    +        else
                 GE_GREATER
    -        }
    -    } else {
    -        if (aInt > bInt) {
    +    else
    +        if (aInt > bInt)
                 GE_LESS
    -        } else if (aInt == bInt) {
    +        else if (aInt == bInt)
                 GE_EQUAL
    -        } else {
    +        else
                 GE_GREATER
    -        }
    -    };
    +    ;
     }
     
     pub extern fn __unordtf2(a: f128, b: f128) -> c_int {
    diff --git a/test/cases/align.zig b/test/cases/align.zig
    index 3bf0d9c9af..3105945e04 100644
    --- a/test/cases/align.zig
    +++ b/test/cases/align.zig
    @@ -10,7 +10,7 @@ test "global variable alignment" {
         assert(@typeOf(slice) == []align(4) u8);
     }
     
    -fn derp() align(@sizeOf(usize) * 2) -> i32 { 1234 }
    +fn derp() align(@sizeOf(usize) * 2) -> i32 { return 1234; }
     fn noop1() align(1) {}
     fn noop4() align(4) {}
     
    @@ -53,14 +53,14 @@ test "implicitly decreasing pointer alignment" {
         assert(addUnaligned(&a, &b) == 7);
     }
     
    -fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { *a + *b }
    +fn addUnaligned(a: &align(1) const u32, b: &align(1) const u32) -> u32 { return *a + *b; }
     
     test "implicitly decreasing slice alignment" {
         const a: u32 align(4) = 3;
         const b: u32 align(8) = 4;
         assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);
     }
    -fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { a[0] + b[0] }
    +fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) -> u32 { return a[0] + b[0]; }
     
     test "specifying alignment allows pointer cast" {
         testBytesAlign(0x33);
    @@ -115,20 +115,20 @@ fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) -> i32, answer: i32) {
         assert(ptr() == answer);
     }
     
    -fn alignedSmall() align(8) -> i32 { 1234 }
    -fn alignedBig() align(16) -> i32 { 5678 }
    +fn alignedSmall() align(8) -> i32 { return 1234; }
    +fn alignedBig() align(16) -> i32 { return 5678; }
     
     
     test "@alignCast functions" {
         assert(fnExpectsOnly1(simple4) == 0x19);
     }
     fn fnExpectsOnly1(ptr: fn()align(1) -> i32) -> i32 {
    -    fnExpects4(@alignCast(4, ptr))
    +    return fnExpects4(@alignCast(4, ptr));
     }
     fn fnExpects4(ptr: fn()align(4) -> i32) -> i32 {
    -    ptr()
    +    return ptr();
     }
    -fn simple4() align(4) -> i32 { 0x19 }
    +fn simple4() align(4) -> i32 { return 0x19; }
     
     
     test "generic function with align param" {
    @@ -137,7 +137,7 @@ test "generic function with align param" {
         assert(whyWouldYouEverDoThis(8) == 0x1);
     }
     
    -fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { 0x1 }
    +fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) -> u8 { return 0x1; }
     
     
     test "@ptrCast preserves alignment of bigger source" {
    diff --git a/test/cases/array.zig b/test/cases/array.zig
    index a6fa07b004..bf77e51fee 100644
    --- a/test/cases/array.zig
    +++ b/test/cases/array.zig
    @@ -22,7 +22,7 @@ test "arrays" {
         assert(getArrayLen(array) == 5);
     }
     fn getArrayLen(a: []const u32) -> usize {
    -    a.len
    +    return a.len;
     }
     
     test "void arrays" {
    @@ -41,7 +41,7 @@ test "array literal" {
     }
     
     test "array dot len const expr" {
    -    assert(comptime {some_array.len == 4});
    +    assert(comptime x: {break :x some_array.len == 4;});
     }
     
     const ArrayDotLenConstExpr = struct {
    diff --git a/test/cases/bitcast.zig b/test/cases/bitcast.zig
    index 72ca24cf5e..0a92d9d606 100644
    --- a/test/cases/bitcast.zig
    +++ b/test/cases/bitcast.zig
    @@ -10,5 +10,5 @@ fn testBitCast_i32_u32() {
         assert(conv2(@maxValue(u32)) == -1);
     }
     
    -fn conv(x: i32) -> u32 { @bitCast(u32, x) }
    -fn conv2(x: u32) -> i32 { @bitCast(i32, x) }
    +fn conv(x: i32) -> u32 { return @bitCast(u32, x); }
    +fn conv2(x: u32) -> i32 { return @bitCast(i32, x); }
    diff --git a/test/cases/bool.zig b/test/cases/bool.zig
    index 61bb3bf759..1203e696ba 100644
    --- a/test/cases/bool.zig
    +++ b/test/cases/bool.zig
    @@ -22,7 +22,7 @@ test "bool cmp" {
         assert(testBoolCmp(true, false) == false);
     }
     fn testBoolCmp(a: bool, b: bool) -> bool {
    -    a == b
    +    return a == b;
     }
     
     const global_f = false;
    diff --git a/test/cases/cast.zig b/test/cases/cast.zig
    index c93d2e7413..8b16cb44d4 100644
    --- a/test/cases/cast.zig
    +++ b/test/cases/cast.zig
    @@ -50,7 +50,7 @@ test "peer resolve arrays of different size to const slice" {
         comptime assert(mem.eql(u8, boolToStr(false), "false"));
     }
     fn boolToStr(b: bool) -> []const u8 {
    -    if (b) "true" else "false"
    +    return if (b) "true" else "false";
     }
     
     
    @@ -239,17 +239,17 @@ test "peer type resolution: error and [N]T" {
     
     error BadValue;
     fn testPeerErrorAndArray(x: u8) -> %[]const u8 {
    -    switch (x) {
    +    return switch (x) {
             0x00 => "OK",
             else => error.BadValue,
    -    }
    +    };
     }
     fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
    -    switch (x) {
    +    return switch (x) {
             0x00 => "OK",
             0x01 => "OKK",
             else => error.BadValue,
    -    }
    +    };
     }
     
     test "explicit cast float number literal to integer if no fraction component" {
    @@ -269,11 +269,11 @@ fn testCast128() {
     }
     
     fn cast128Int(x: f128) -> u128 {
    -    @bitCast(u128, x)
    +    return @bitCast(u128, x);
     }
     
     fn cast128Float(x: u128) -> f128 {
    -    @bitCast(f128, x)
    +    return @bitCast(f128, x);
     }
     
     test "const slice widen cast" {
    diff --git a/test/cases/defer.zig b/test/cases/defer.zig
    index 6cafe9f334..d4cb79ec46 100644
    --- a/test/cases/defer.zig
    +++ b/test/cases/defer.zig
    @@ -7,9 +7,9 @@ error FalseNotAllowed;
     
     fn runSomeErrorDefers(x: bool) -> %bool {
         index = 0;
    -    defer {result[index] = 'a'; index += 1;};
    -    %defer {result[index] = 'b'; index += 1;};
    -    defer {result[index] = 'c'; index += 1;};
    +    defer {result[index] = 'a'; index += 1;}
    +    %defer {result[index] = 'b'; index += 1;}
    +    defer {result[index] = 'c'; index += 1;}
         return if (x) x else error.FalseNotAllowed;
     }
     
    @@ -18,9 +18,9 @@ test "mixing normal and error defers" {
         assert(result[0] == 'c');
         assert(result[1] == 'a');
     
    -    const ok = runSomeErrorDefers(false) %% |err| {
    +    const ok = runSomeErrorDefers(false) %% |err| x: {
             assert(err == error.FalseNotAllowed);
    -        true
    +        break :x true;
         };
         assert(ok);
         assert(result[0] == 'c');
    @@ -41,5 +41,5 @@ fn testBreakContInDefer(x: usize) {
                 if (i == 5) break;
             }
             assert(i == 5);
    -    };
    +    }
     }
    diff --git a/test/cases/enum.zig b/test/cases/enum.zig
    index 6352a23afa..26aa8fb589 100644
    --- a/test/cases/enum.zig
    +++ b/test/cases/enum.zig
    @@ -41,7 +41,7 @@ const Bar = enum {
     };
     
     fn returnAnInt(x: i32) -> Foo {
    -    Foo { .One = x }
    +    return Foo { .One = x };
     }
     
     
    diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig
    index ae48a266d0..c28692575e 100644
    --- a/test/cases/enum_with_members.zig
    +++ b/test/cases/enum_with_members.zig
    @@ -8,9 +8,9 @@ const ET = union(enum) {
     
         pub fn print(a: &const ET, buf: []u8) -> %usize {
             return switch (*a) {
    -            ET.SINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
    -            ET.UINT => |x| { fmt.formatIntBuf(buf, x, 10, false, 0) },
    -        }
    +            ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
    +            ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
    +        };
         }
     };
     
    diff --git a/test/cases/error.zig b/test/cases/error.zig
    index 9e55f57b6d..3974e9dc7c 100644
    --- a/test/cases/error.zig
    +++ b/test/cases/error.zig
    @@ -3,7 +3,7 @@ const mem = @import("std").mem;
     
     pub fn foo() -> %i32 {
         const x = %return bar();
    -    return x + 1
    +    return x + 1;
     }
     
     pub fn bar() -> %i32 {
    @@ -21,7 +21,7 @@ test "error wrapping" {
     
     error ItBroke;
     fn gimmeItBroke() -> []const u8 {
    -    @errorName(error.ItBroke)
    +    return @errorName(error.ItBroke);
     }
     
     test "@errorName" {
    @@ -48,7 +48,7 @@ error AnError;
     error AnError;
     error SecondError;
     fn shouldBeNotEqual(a: error, b: error) {
    -    if (a == b) unreachable
    +    if (a == b) unreachable;
     }
     
     
    @@ -60,11 +60,7 @@ test "error binary operator" {
     }
     error ItBroke;
     fn errBinaryOperatorG(x: bool) -> %isize {
    -    if (x) {
    -        error.ItBroke
    -    } else {
    -        isize(10)
    -    }
    +    return if (x) error.ItBroke else isize(10);
     }
     
     
    @@ -72,7 +68,7 @@ test "unwrap simple value from error" {
         const i = %%unwrapSimpleValueFromErrorDo();
         assert(i == 13);
     }
    -fn unwrapSimpleValueFromErrorDo() -> %isize { 13 }
    +fn unwrapSimpleValueFromErrorDo() -> %isize { return 13; }
     
     
     test "error return in assignment" {
    diff --git a/test/cases/eval.zig b/test/cases/eval.zig
    index c657482d08..a2e015fba7 100644
    --- a/test/cases/eval.zig
    +++ b/test/cases/eval.zig
    @@ -44,7 +44,7 @@ test "static function evaluation" {
         assert(statically_added_number == 3);
     }
     const statically_added_number = staticAdd(1, 2);
    -fn staticAdd(a: i32, b: i32) -> i32 { a + b }
    +fn staticAdd(a: i32, b: i32) -> i32 { return a + b; }
     
     
     test "const expr eval on single expr blocks" {
    @@ -54,10 +54,10 @@ test "const expr eval on single expr blocks" {
     fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) -> i32 {
         const literal = 3;
     
    -    const result = if (b) {
    -        literal
    -    } else {
    -        x
    +    const result = if (b) b: {
    +        break :b literal;
    +    } else b: {
    +        break :b x;
         };
     
         return result;
    @@ -94,9 +94,9 @@ pub const Vec3 = struct {
         data: [3]f32,
     };
     pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
    -    Vec3 {
    +    return Vec3 {
             .data = []f32 { x, y, z, },
    -    }
    +    };
     }
     
     
    @@ -176,7 +176,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
         }
     }
     fn letsTryToCompareBools(a: bool, b: bool) -> bool {
    -    max(bool, a, b)
    +    return max(bool, a, b);
     }
     test "inlined block and runtime block phi" {
         assert(letsTryToCompareBools(true, true));
    @@ -202,9 +202,9 @@ const cmd_fns = []CmdFn{
         CmdFn {.name = "two", .func = two},
         CmdFn {.name = "three", .func = three},
     };
    -fn one(value: i32) -> i32 { value + 1 }
    -fn two(value: i32) -> i32 { value + 2 }
    -fn three(value: i32) -> i32 { value + 3 }
    +fn one(value: i32) -> i32 { return value + 1; }
    +fn two(value: i32) -> i32 { return value + 2; }
    +fn three(value: i32) -> i32 { return value + 3; }
     
     fn performFn(comptime prefix_char: u8, start_value: i32) -> i32 {
         var result: i32 = start_value;
    @@ -317,12 +317,12 @@ test "create global array with for loop" {
         assert(global_array[9] == 9 * 9);
     }
     
    -const global_array = {
    +const global_array = x: {
         var result: [10]usize = undefined;
         for (result) |*item, index| {
             *item = index * index;
         }
    -    result
    +    break :x result;
     };
     
     test "compile-time downcast when the bits fit" {
    diff --git a/test/cases/fn.zig b/test/cases/fn.zig
    index c948d8af3d..aad68447b2 100644
    --- a/test/cases/fn.zig
    +++ b/test/cases/fn.zig
    @@ -4,7 +4,7 @@ test "params" {
         assert(testParamsAdd(22, 11) == 33);
     }
     fn testParamsAdd(a: i32, b: i32) -> i32 {
    -    a + b
    +    return a + b;
     }
     
     
    @@ -22,7 +22,7 @@ test "void parameters" {
     }
     fn voidFun(a: i32, b: void, c: i32, d: void) {
         const v = b;
    -    const vv: void = if (a == 1) {v} else {};
    +    const vv: void = if (a == 1) v else {};
         assert(a + c == 3);
         return vv;
     }
    @@ -45,9 +45,9 @@ test "separate block scopes" {
             assert(no_conflict == 5);
         }
     
    -    const c = {
    +    const c = x: {
             const no_conflict = i32(10);
    -        no_conflict
    +        break :x no_conflict;
         };
         assert(c == 10);
     }
    @@ -73,7 +73,7 @@ test "implicit cast function unreachable return" {
     fn wantsFnWithVoid(f: fn()) { }
     
     fn fnWithUnreachable() -> noreturn {
    -    unreachable
    +    unreachable;
     }
     
     
    @@ -83,14 +83,14 @@ test "function pointers" {
             assert(f() == u32(i) + 5);
         }
     }
    -fn fn1() -> u32 {5}
    -fn fn2() -> u32 {6}
    -fn fn3() -> u32 {7}
    -fn fn4() -> u32 {8}
    +fn fn1() -> u32 {return 5;}
    +fn fn2() -> u32 {return 6;}
    +fn fn3() -> u32 {return 7;}
    +fn fn4() -> u32 {return 8;}
     
     
     test "inline function call" {
         assert(@inlineCall(add, 3, 9) == 12);
     }
     
    -fn add(a: i32, b: i32) -> i32 { a + b }
    +fn add(a: i32, b: i32) -> i32 { return a + b; }
    diff --git a/test/cases/for.zig b/test/cases/for.zig
    index e4b8094cf5..5a7919541f 100644
    --- a/test/cases/for.zig
    +++ b/test/cases/for.zig
    @@ -12,7 +12,7 @@ test "continue in for loop" {
             }
             break;
         }
    -    if (sum != 6) unreachable
    +    if (sum != 6) unreachable;
     }
     
     test "for loop with pointer elem var" {
    diff --git a/test/cases/generics.zig b/test/cases/generics.zig
    index d6a3192a6b..96500e39b2 100644
    --- a/test/cases/generics.zig
    +++ b/test/cases/generics.zig
    @@ -11,7 +11,7 @@ fn max(comptime T: type, a: T, b: T) -> T {
     }
     
     fn add(comptime a: i32, b: i32) -> i32 {
    -    return (comptime {a}) + b;
    +    return (comptime a) + b;
     }
     
     const the_max = max(u32, 1234, 5678);
    @@ -20,15 +20,15 @@ test "compile time generic eval" {
     }
     
     fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
    -    max(u32, a, b)
    +    return max(u32, a, b);
     }
     
     fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
    -    max(u32, a, b)
    +    return max(u32, a, b);
     }
     
     fn sameButWithFloats(a: f64, b: f64) -> f64 {
    -    max(f64, a, b)
    +    return max(f64, a, b);
     }
     
     test "fn with comptime args" {
    @@ -49,28 +49,28 @@ comptime {
     }
     
     fn max_var(a: var, b: var) -> @typeOf(a + b) {
    -    if (a > b) a else b
    +    return if (a > b) a else b;
     }
     
     fn max_i32(a: i32, b: i32) -> i32 {
    -    max_var(a, b)
    +    return max_var(a, b);
     }
     
     fn max_f64(a: f64, b: f64) -> f64 {
    -    max_var(a, b)
    +    return max_var(a, b);
     }
     
     
     pub fn List(comptime T: type) -> type {
    -    SmallList(T, 8)
    +    return SmallList(T, 8);
     }
     
     pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
    -    struct {
    +    return struct {
             items: []T,
             length: usize,
             prealloc_items: [STATIC_SIZE]T,
    -    }
    +    };
     }
     
     test "function with return type type" {
    @@ -91,20 +91,20 @@ test "generic struct" {
         assert(b1.getVal());
     }
     fn GenNode(comptime T: type) -> type {
    -    struct {
    +    return struct {
             value: T,
             next: ?&GenNode(T),
    -        fn getVal(n: &const GenNode(T)) -> T { n.value }
    -    }
    +        fn getVal(n: &const GenNode(T)) -> T { return n.value; }
    +    };
     }
     
     test "const decls in struct" {
         assert(GenericDataThing(3).count_plus_one == 4);
     }
     fn GenericDataThing(comptime count: isize) -> type {
    -    struct {
    +    return struct {
             const count_plus_one = count + 1;
    -    }
    +    };
     }
     
     
    @@ -120,16 +120,16 @@ test "generic fn with implicit cast" {
         assert(getFirstByte(u8, []u8 {13}) == 13);
         assert(getFirstByte(u16, []u16 {0, 13}) == 0);
     }
    -fn getByte(ptr: ?&const u8) -> u8 {*??ptr}
    +fn getByte(ptr: ?&const u8) -> u8 {return *??ptr;}
     fn getFirstByte(comptime T: type, mem: []const T) -> u8 {
    -    getByte(@ptrCast(&const u8, &mem[0]))
    +    return getByte(@ptrCast(&const u8, &mem[0]));
     }
     
     
     const foos = []fn(var) -> bool { foo1, foo2 };
     
    -fn foo1(arg: var) -> bool { arg }
    -fn foo2(arg: var) -> bool { !arg }
    +fn foo1(arg: var) -> bool { return arg; }
    +fn foo2(arg: var) -> bool { return !arg; }
     
     test "array of generic fns" {
         assert(foos[0](true));
    diff --git a/test/cases/if.zig b/test/cases/if.zig
    index 10fedcdea5..d1fa717b50 100644
    --- a/test/cases/if.zig
    +++ b/test/cases/if.zig
    @@ -29,10 +29,10 @@ test "else if expression" {
     }
     fn elseIfExpressionF(c: u8) -> u8 {
         if (c == 0) {
    -        0
    +        return 0;
         } else if (c == 1) {
    -        1
    +        return 1;
         } else {
    -        u8(2)
    +        return u8(2);
         }
     }
    diff --git a/test/cases/import/a_namespace.zig b/test/cases/import/a_namespace.zig
    index d6926fbb5e..40cdd69139 100644
    --- a/test/cases/import/a_namespace.zig
    +++ b/test/cases/import/a_namespace.zig
    @@ -1 +1 @@
    -pub fn foo() -> i32 { 1234 }
    +pub fn foo() -> i32 { return 1234; }
    diff --git a/test/cases/ir_block_deps.zig b/test/cases/ir_block_deps.zig
    index e6ce12bd65..a70dff0c84 100644
    --- a/test/cases/ir_block_deps.zig
    +++ b/test/cases/ir_block_deps.zig
    @@ -8,10 +8,10 @@ fn foo(id: u64) -> %i32 {
                 return %return getErrInt();
             },
             else => error.ItBroke,
    -    }
    +    };
     }
     
    -fn getErrInt() -> %i32 { 0 }
    +fn getErrInt() -> %i32 { return 0; }
     
     error ItBroke;
     
    diff --git a/test/cases/math.zig b/test/cases/math.zig
    index 1d29800aad..b4e0e4cfd6 100644
    --- a/test/cases/math.zig
    +++ b/test/cases/math.zig
    @@ -28,16 +28,16 @@ fn testDivision() {
         assert(divTrunc(f32, -5.0, 3.0) == -1.0);
     }
     fn div(comptime T: type, a: T, b: T) -> T {
    -    a / b
    +    return a / b;
     }
     fn divExact(comptime T: type, a: T, b: T) -> T {
    -    @divExact(a, b)
    +    return @divExact(a, b);
     }
     fn divFloor(comptime T: type, a: T, b: T) -> T {
    -    @divFloor(a, b)
    +    return @divFloor(a, b);
     }
     fn divTrunc(comptime T: type, a: T, b: T) -> T {
    -    @divTrunc(a, b)
    +    return @divTrunc(a, b);
     }
     
     test "@addWithOverflow" {
    @@ -71,7 +71,7 @@ fn testClz() {
     }
     
     fn clz(x: var) -> usize {
    -    @clz(x)
    +    return @clz(x);
     }
     
     test "@ctz" {
    @@ -86,7 +86,7 @@ fn testCtz() {
     }
     
     fn ctz(x: var) -> usize {
    -    @ctz(x)
    +    return @ctz(x);
     }
     
     test "assignment operators" {
    @@ -180,10 +180,10 @@ fn test_u64_div() {
         assert(result.remainder == 100663296);
     }
     fn divWithResult(a: u64, b: u64) -> DivResult {
    -    DivResult {
    +    return DivResult {
             .quotient = a / b,
             .remainder = a % b,
    -    }
    +    };
     }
     const DivResult = struct {
         quotient: u64,
    @@ -191,8 +191,8 @@ const DivResult = struct {
     };
     
     test "binary not" {
    -    assert(comptime {~u16(0b1010101010101010) == 0b0101010101010101});
    -    assert(comptime {~u64(2147483647) == 18446744071562067968});
    +    assert(comptime x: {break :x ~u16(0b1010101010101010) == 0b0101010101010101;});
    +    assert(comptime x: {break :x ~u64(2147483647) == 18446744071562067968;});
         testBinaryNot(0b1010101010101010);
     }
     
    @@ -331,7 +331,7 @@ test "f128" {
         comptime test_f128();
     }
     
    -fn make_f128(x: f128) -> f128 { x }
    +fn make_f128(x: f128) -> f128 { return x; }
     
     fn test_f128() {
         assert(@sizeOf(f128) == 16);
    diff --git a/test/cases/misc.zig b/test/cases/misc.zig
    index daa7c3eb98..e456ca529a 100644
    --- a/test/cases/misc.zig
    +++ b/test/cases/misc.zig
    @@ -110,17 +110,17 @@ fn testShortCircuit(f: bool, t: bool) {
         var hit_3 = f;
         var hit_4 = f;
     
    -    if (t or {assert(f); f}) {
    +    if (t or x: {assert(f); break :x f;}) {
             hit_1 = t;
         }
    -    if (f or { hit_2 = t; f }) {
    +    if (f or x: { hit_2 = t; break :x f; }) {
             assert(f);
         }
     
    -    if (t and { hit_3 = t; f }) {
    +    if (t and x: { hit_3 = t; break :x f; }) {
             assert(f);
         }
    -    if (f and {assert(f); f}) {
    +    if (f and x: {assert(f); break :x f;}) {
             assert(f);
         } else {
             hit_4 = t;
    @@ -135,11 +135,11 @@ test "truncate" {
         assert(testTruncate(0x10fd) == 0xfd);
     }
     fn testTruncate(x: u32) -> u8 {
    -    @truncate(u8, x)
    +    return @truncate(u8, x);
     }
     
     fn first4KeysOfHomeRow() -> []const u8 {
    -    "aoeu"
    +    return "aoeu";
     }
     
     test "return string from function" {
    @@ -167,7 +167,7 @@ test "memcpy and memset intrinsics" {
     }
     
     test "builtin static eval" {
    -    const x : i32 = comptime {1 + 2 + 3};
    +    const x : i32 = comptime x: {break :x 1 + 2 + 3;};
         assert(x == comptime 6);
     }
     
    @@ -190,7 +190,7 @@ test "slicing" {
     
     test "constant equal function pointers" {
         const alias = emptyFn;
    -    assert(comptime {emptyFn == alias});
    +    assert(comptime x: {break :x emptyFn == alias;});
     }
     
     fn emptyFn() {}
    @@ -280,14 +280,14 @@ test "cast small unsigned to larger signed" {
         assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
         assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
     }
    -fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { x }
    -fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { x }
    +fn castSmallUnsignedToLargerSigned1(x: u8) -> i16 { return x; }
    +fn castSmallUnsignedToLargerSigned2(x: u16) -> i64 { return x; }
     
     
     test "implicit cast after unreachable" {
         assert(outer() == 1234);
     }
    -fn inner() -> i32 { 1234 }
    +fn inner() -> i32 { return 1234; }
     fn outer() -> i64 {
         return inner();
     }
    @@ -310,8 +310,8 @@ test "call result of if else expression" {
     fn f2(x: bool) -> []const u8 {
         return (if (x) fA else fB)();
     }
    -fn fA() -> []const u8 { "a" }
    -fn fB() -> []const u8 { "b" }
    +fn fA() -> []const u8 { return "a"; }
    +fn fB() -> []const u8 { return "b"; }
     
     
     test "const expression eval handling of variables" {
    @@ -379,7 +379,7 @@ test "pointer comparison" {
         assert(ptrEql(b, b));
     }
     fn ptrEql(a: &const []const u8, b: &const []const u8) -> bool {
    -    a == b
    +    return a == b;
     }
     
     
    @@ -483,7 +483,7 @@ test "@typeId" {
             assert(@typeId(AUnion) == Tid.Union);
             assert(@typeId(fn()) == Tid.Fn);
             assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
    -        assert(@typeId(@typeOf({this})) == Tid.Block);
    +        assert(@typeId(@typeOf(x: {break :x this;})) == Tid.Block);
             // TODO bound fn
             // TODO arg tuple
             // TODO opaque
    diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig
    index cbd98d212f..9b298f8823 100644
    --- a/test/cases/reflection.zig
    +++ b/test/cases/reflection.zig
    @@ -22,7 +22,7 @@ test "reflection: function return type, var args, and param types" {
         }
     }
     
    -fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
    +fn dummy(a: bool, b: i32, c: f32) -> i32 { return 1234; }
     fn dummy_varargs(args: ...) {}
     
     test "reflection: struct member types and names" {
    diff --git a/test/cases/struct.zig b/test/cases/struct.zig
    index 1a9a03c71a..28792e9a73 100644
    --- a/test/cases/struct.zig
    +++ b/test/cases/struct.zig
    @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
     const builtin = @import("builtin");
     
     const StructWithNoFields = struct {
    -    fn add(a: i32, b: i32) -> i32 { a + b }
    +    fn add(a: i32, b: i32) -> i32 { return a + b; }
     };
     const empty_global_instance = StructWithNoFields {};
     
    @@ -109,7 +109,7 @@ const Foo = struct {
         ptr: fn() -> i32,
     };
     
    -fn aFunc() -> i32 { 13 }
    +fn aFunc() -> i32 { return 13; }
     
     fn callStructField(foo: &const Foo) -> i32 {
         return foo.ptr();
    @@ -124,7 +124,7 @@ test "store member function in variable" {
     }
     const MemberFnTestFoo = struct {
         x: i32,
    -    fn member(foo: &const MemberFnTestFoo) -> i32 { foo.x }
    +    fn member(foo: &const MemberFnTestFoo) -> i32 { return foo.x; }
     };
     
     
    @@ -141,7 +141,7 @@ test "member functions" {
     const MemberFnRand = struct {
         seed: u32,
         pub fn getSeed(r: &const MemberFnRand) -> u32 {
    -        r.seed
    +        return r.seed;
         }
     };
     
    @@ -154,10 +154,10 @@ const Bar = struct {
         y: i32,
     };
     fn makeBar(x: i32, y: i32) -> Bar {
    -    Bar {
    +    return Bar {
             .x = x,
             .y = y,
    -    }
    +    };
     }
     
     test "empty struct method call" {
    @@ -166,7 +166,7 @@ test "empty struct method call" {
     }
     const EmptyStruct = struct {
         fn method(es: &const EmptyStruct) -> i32 {
    -        1234
    +        return 1234;
         }
     };
     
    @@ -176,14 +176,14 @@ test "return empty struct from fn" {
     }
     const EmptyStruct2 = struct {};
     fn testReturnEmptyStructFromFn() -> EmptyStruct2 {
    -    EmptyStruct2 {}
    +    return EmptyStruct2 {};
     }
     
     test "pass slice of empty struct to fn" {
         assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{ EmptyStruct2{} }) == 1);
     }
     fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) -> usize {
    -    slice.len
    +    return slice.len;
     }
     
     const APackedStruct = packed struct {
    diff --git a/test/cases/switch.zig b/test/cases/switch.zig
    index 11c2178427..878c0af9e4 100644
    --- a/test/cases/switch.zig
    +++ b/test/cases/switch.zig
    @@ -21,12 +21,12 @@ test "switch with all ranges" {
     }
     
     fn testSwitchWithAllRanges(x: u32, y: u32) -> u32 {
    -    switch (x) {
    +    return switch (x) {
             0 ... 100 => 1,
             101 ... 200 => 2,
             201 ... 300 => 3,
             else => y,
    -    }
    +    };
     }
     
     test "implicit comptime switch" {
    @@ -132,7 +132,7 @@ test "switch with multiple expressions" {
         assert(x == 2);
     }
     fn returnsFive() -> i32 {
    -    5
    +    return 5;
     }
     
     
    @@ -161,10 +161,10 @@ test "switch on type" {
     }
     
     fn trueIfBoolFalseOtherwise(comptime T: type) -> bool {
    -    switch (T) {
    +    return switch (T) {
             bool => true,
             else => false,
    -    }
    +    };
     }
     
     test "switch handles all cases of number" {
    @@ -186,22 +186,22 @@ fn testSwitchHandleAllCases() {
     }
     
     fn testSwitchHandleAllCasesExhaustive(x: u2) -> u2 {
    -    switch (x) {
    +    return switch (x) {
             0 => u2(3),
             1 => 2,
             2 => 1,
             3 => 0,
    -    }
    +    };
     }
     
     fn testSwitchHandleAllCasesRange(x: u8) -> u8 {
    -    switch (x) {
    +    return switch (x) {
             0 ... 100 => u8(0),
             101 ... 200 => 1,
             201, 203 => 2,
             202 => 4,
             204 ... 255 => 3,
    -    }
    +    };
     }
     
     test "switch all prongs unreachable" {
    diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig
    index 21f6b04037..be15193c74 100644
    --- a/test/cases/switch_prong_err_enum.zig
    +++ b/test/cases/switch_prong_err_enum.zig
    @@ -18,7 +18,7 @@ fn doThing(form_id: u64) -> %FormValue {
         return switch (form_id) {
             17 => FormValue { .Address = %return readOnce() },
             else => error.InvalidDebugInfo,
    -    }
    +    };
     }
     
     test "switch prong returns error enum" {
    diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/cases/switch_prong_implicit_cast.zig
    index e7fe53b841..9e7c091494 100644
    --- a/test/cases/switch_prong_implicit_cast.zig
    +++ b/test/cases/switch_prong_implicit_cast.zig
    @@ -8,11 +8,11 @@ const FormValue = union(enum) {
     error Whatever;
     
     fn foo(id: u64) -> %FormValue {
    -    switch (id) {
    +    return switch (id) {
             2 => FormValue { .Two = true },
             1 => FormValue { .One = {} },
             else => return error.Whatever,
    -    }
    +    };
     }
     
     test "switch prong implicit cast" {
    diff --git a/test/cases/this.zig b/test/cases/this.zig
    index b64c52a098..b4e6b32a09 100644
    --- a/test/cases/this.zig
    +++ b/test/cases/this.zig
    @@ -3,7 +3,7 @@ const assert = @import("std").debug.assert;
     const module = this;
     
     fn Point(comptime T: type) -> type {
    -    struct {
    +    return struct {
             const Self = this;
             x: T,
             y: T,
    @@ -12,20 +12,16 @@ fn Point(comptime T: type) -> type {
                 self.x += 1;
                 self.y += 1;
             }
    -    }
    +    };
     }
     
     fn add(x: i32, y: i32) -> i32 {
    -    x + y
    +    return x + y;
     }
     
     fn factorial(x: i32) -> i32 {
         const selfFn = this;
    -    if (x == 0) {
    -        1
    -    } else {
    -        x * selfFn(x - 1)
    -    }
    +    return if (x == 0) 1 else x * selfFn(x - 1);
     }
     
     test "this refer to module call private fn" {
    diff --git a/test/cases/try.zig b/test/cases/try.zig
    index 2505443712..25b2f321fb 100644
    --- a/test/cases/try.zig
    +++ b/test/cases/try.zig
    @@ -7,9 +7,9 @@ test "try on error union" {
     }
     
     fn tryOnErrorUnionImpl() {
    -    const x = if (returnsTen()) |val| {
    +    const x = if (returnsTen()) |val|
             val + 1
    -    } else |err| switch (err) {
    +    else |err| switch (err) {
             error.ItBroke, error.NoMem => 1,
             error.CrappedOut => i32(2),
             else => unreachable,
    @@ -21,22 +21,14 @@ error ItBroke;
     error NoMem;
     error CrappedOut;
     fn returnsTen() -> %i32 {
    -    10
    +    return 10;
     }
     
     test "try without vars" {
    -    const result1 = if (failIfTrue(true)) {
    -        1
    -    } else |_| {
    -        i32(2)
    -    };
    +    const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
         assert(result1 == 2);
     
    -    const result2 = if (failIfTrue(false)) {
    -        1
    -    } else |_| {
    -        i32(2)
    -    };
    +    const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
         assert(result2 == 1);
     }
     
    diff --git a/test/cases/var_args.zig b/test/cases/var_args.zig
    index 363816bc8a..7d16106362 100644
    --- a/test/cases/var_args.zig
    +++ b/test/cases/var_args.zig
    @@ -58,8 +58,8 @@ fn extraFn(extra: u32, args: ...) -> usize {
     
     const foos = []fn(...) -> bool { foo1, foo2 };
     
    -fn foo1(args: ...) -> bool { true }
    -fn foo2(args: ...) -> bool { false }
    +fn foo1(args: ...) -> bool { return true; }
    +fn foo2(args: ...) -> bool { return false; }
     
     test "array of var args functions" {
         assert(foos[0]());
    diff --git a/test/cases/while.zig b/test/cases/while.zig
    index c16171d4a3..e61fe1f9d2 100644
    --- a/test/cases/while.zig
    +++ b/test/cases/while.zig
    @@ -118,73 +118,61 @@ test "while with error union condition" {
     var numbers_left: i32 = undefined;
     error OutOfNumbers;
     fn getNumberOrErr() -> %i32 {
    -    return if (numbers_left == 0) {
    +    return if (numbers_left == 0)
             error.OutOfNumbers
    -    } else {
    +    else x: {
             numbers_left -= 1;
    -        numbers_left
    +        break :x numbers_left;
         };
     }
     fn getNumberOrNull() -> ?i32 {
    -    return if (numbers_left == 0) {
    +    return if (numbers_left == 0)
             null
    -    } else {
    +    else x: {
             numbers_left -= 1;
    -        numbers_left
    +        break :x numbers_left;
         };
     }
     
     test "while on nullable with else result follow else prong" {
         const result = while (returnNull()) |value| {
             break value;
    -    } else {
    -        i32(2)
    -    };
    +    } else i32(2);
         assert(result == 2);
     }
     
     test "while on nullable with else result follow break prong" {
         const result = while (returnMaybe(10)) |value| {
             break value;
    -    } else {
    -        i32(2)
    -    };
    +    } else i32(2);
         assert(result == 10);
     }
     
     test "while on error union with else result follow else prong" {
         const result = while (returnError()) |value| {
             break value;
    -    } else |err| {
    -        i32(2)
    -    };
    +    } else |err| i32(2);
         assert(result == 2);
     }
     
     test "while on error union with else result follow break prong" {
         const result = while (returnSuccess(10)) |value| {
             break value;
    -    } else |err| {
    -        i32(2)
    -    };
    +    } else |err| i32(2);
         assert(result == 10);
     }
     
     test "while on bool with else result follow else prong" {
         const result = while (returnFalse()) {
             break i32(10);
    -    } else {
    -        i32(2)
    -    };
    +    } else i32(2);
         assert(result == 2);
     }
     
     test "while on bool with else result follow break prong" {
         const result = while (returnTrue()) {
             break i32(10);
    -    } else {
    -        i32(2)
    -    };
    +    } else i32(2);
         assert(result == 10);
     }
     
    @@ -215,10 +203,10 @@ fn testContinueOuter() {
         }
     }
     
    -fn returnNull() -> ?i32 { null }
    -fn returnMaybe(x: i32) -> ?i32 { x }
    +fn returnNull() -> ?i32 { return null; }
    +fn returnMaybe(x: i32) -> ?i32 { return x; }
     error YouWantedAnError;
    -fn returnError() -> %i32 { error.YouWantedAnError }
    -fn returnSuccess(x: i32) -> %i32 { x }
    -fn returnFalse() -> bool { false }
    -fn returnTrue() -> bool { true }
    +fn returnError() -> %i32 { return error.YouWantedAnError; }
    +fn returnSuccess(x: i32) -> %i32 { return x; }
    +fn returnFalse() -> bool { return false; }
    +fn returnTrue() -> bool { return true; }
    diff --git a/test/compare_output.zig b/test/compare_output.zig
    index ad9c91ff20..88e25bf40c 100644
    --- a/test/compare_output.zig
    +++ b/test/compare_output.zig
    @@ -10,7 +10,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\}
         , "Hello, world!" ++ os.line_sep);
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("multiple files with private function",
                 \\use @import("std").io;
                 \\use @import("foo.zig");
    @@ -41,10 +41,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
                 \\}
             );
     
    -        tc
    +        break :x tc;
         });
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("import segregation",
                 \\use @import("foo.zig");
                 \\use @import("bar.zig");
    @@ -82,10 +82,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
                 \\}
             );
     
    -        tc
    +        break :x tc;
         });
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("two files use import each other",
                 \\use @import("a.zig");
                 \\
    @@ -112,7 +112,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
                 \\pub const b_text = a_text;
             );
     
    -        tc
    +        break :x tc;
         });
     
         cases.add("hello world without libc",
    @@ -286,11 +286,11 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    const a_int = @ptrCast(&align(1) i32, a ?? unreachable);
             \\    const b_int = @ptrCast(&align(1) i32, b ?? unreachable);
             \\    if (*a_int < *b_int) {
    -        \\        -1
    +        \\        return -1;
             \\    } else if (*a_int > *b_int) {
    -        \\        1
    +        \\        return 1;
             \\    } else {
    -        \\        c_int(0)
    +        \\        return 0;
             \\    }
             \\}
             \\
    @@ -342,13 +342,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\const Foo = struct {
             \\    field1: Bar,
             \\
    -        \\    fn method(a: &const Foo) -> bool { true }
    +        \\    fn method(a: &const Foo) -> bool { return true; }
             \\};
             \\
             \\const Bar = struct {
             \\    field2: i32,
             \\
    -        \\    fn method(b: &const Bar) -> bool { true }
    +        \\    fn method(b: &const Bar) -> bool { return true; }
             \\};
             \\
             \\pub fn main() -> %void {
    @@ -429,7 +429,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\fn its_gonna_pass() -> %void { }
         , "before\nafter\ndefer3\ndefer1\n");
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("@embedFile",
                 \\const foo_txt = @embedFile("foo.txt");
                 \\const io = @import("std").io;
    @@ -442,10 +442,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
     
             tc.addSourceFile("foo.txt", "1234\nabcd\n");
     
    -        tc
    +        break :x tc;
         });
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("parsing args",
                 \\const std = @import("std");
                 \\const io = std.io;
    @@ -483,10 +483,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
                 "last arg",
             });
     
    -        tc
    +        break :x tc;
         });
     
    -    cases.addCase({
    +    cases.addCase(x: {
             var tc = cases.create("parsing args new API",
                 \\const std = @import("std");
                 \\const io = std.io;
    @@ -524,6 +524,6 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
                 "last arg",
             });
     
    -        tc
    +        break :x tc;
         });
     }
    diff --git a/test/compile_errors.zig b/test/compile_errors.zig
    index 3446acda02..60e5c3614d 100644
    --- a/test/compile_errors.zig
    +++ b/test/compile_errors.zig
    @@ -9,7 +9,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\        }
             \\    }
             \\}
    -    , ".tmp_source.zig:4:13: error: labeled loop not found: 'outer'");
    +    , ".tmp_source.zig:4:13: error: label not found: 'outer'");
     
         cases.add("labeled continue not found",
             \\export fn entry() {
    @@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - block expr",
             \\export fn entry() {
    @@ -48,7 +48,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - comptime statement",
             \\export fn entry() {
    @@ -57,7 +57,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    comptime ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - comptime expression",
             \\export fn entry() {
    @@ -66,7 +66,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = comptime {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - defer",
             \\export fn entry() {
    @@ -84,7 +84,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    if(true) ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if expression",
             \\export fn entry() {
    @@ -93,7 +93,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = if(true) {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else statement",
             \\export fn entry() {
    @@ -102,7 +102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    if(true) ({}) else ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else expression",
             \\export fn entry() {
    @@ -111,7 +111,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = if(true) {} else {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else-if statement",
             \\export fn entry() {
    @@ -120,7 +120,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    if(true) ({}) else if(true) ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else-if expression",
             \\export fn entry() {
    @@ -129,7 +129,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = if(true) {} else if(true) {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else-if-else statement",
             \\export fn entry() {
    @@ -138,7 +138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    if(true) ({}) else if(true) ({}) else ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - if-else-if-else expression",
             \\export fn entry() {
    @@ -147,7 +147,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = if(true) {} else if(true) {} else {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - test statement",
             \\export fn entry() {
    @@ -156,7 +156,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    if (foo()) |_| ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - test expression",
             \\export fn entry() {
    @@ -165,7 +165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = if (foo()) |_| {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - while statement",
             \\export fn entry() {
    @@ -174,7 +174,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    while(true) ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - while expression",
             \\export fn entry() {
    @@ -183,7 +183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = while(true) {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - while-continue statement",
             \\export fn entry() {
    @@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    while(true):({}) ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - while-continue expression",
             \\export fn entry() {
    @@ -201,7 +201,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = while(true):({}) {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - for statement",
             \\export fn entry() {
    @@ -210,7 +210,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    for(foo()) ({})
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("implicit semicolon - for expression",
             \\export fn entry() {
    @@ -219,7 +219,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    _ = for(foo()) {}
             \\    var bad = {};
             \\}
    -    , ".tmp_source.zig:5:5: error: invalid token: 'var'");
    +    , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
     
         cases.add("multiple function definitions",
             \\fn a() {}
    @@ -276,12 +276,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("undeclared identifier",
             \\export fn a() {
    +        \\    return
             \\    b +
    -        \\    c
    +        \\    c;
             \\}
         ,
    -            ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
    -            ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'");
    +            ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
    +            ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
     
         cases.add("parameter redeclaration",
             \\fn f(a : i32, a : i32) {
    @@ -306,9 +307,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         cases.add("variable has wrong type",
             \\export fn f() -> i32 {
             \\    const a = c"a";
    -        \\    a
    +        \\    return a;
             \\}
    -    , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'");
    +    , ".tmp_source.zig:3:12: error: expected type 'i32', found '&const u8'");
     
         cases.add("if condition is bool, not int",
             \\export fn f() {
    @@ -393,23 +394,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("missing else clause",
             \\fn f(b: bool) {
    -        \\    const x : i32 = if (b) { 1 };
    -        \\    const y = if (b) { i32(1) };
    +        \\    const x : i32 = if (b) h: { break :h 1; };
    +        \\    const y = if (b) h: { break :h i32(1); };
             \\}
             \\export fn entry() { f(true); }
    -    , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'",
    +    , ".tmp_source.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
                      ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'");
     
         cases.add("direct struct loop",
             \\const A = struct { a : A, };
    -        \\export fn entry() -> usize { @sizeOf(A) }
    +        \\export fn entry() -> usize { return @sizeOf(A); }
         , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
     
         cases.add("indirect struct loop",
             \\const A = struct { b : B, };
             \\const B = struct { c : C, };
             \\const C = struct { a : A, };
    -        \\export fn entry() -> usize { @sizeOf(A) }
    +        \\export fn entry() -> usize { return @sizeOf(A); }
         , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
     
         cases.add("invalid struct field",
    @@ -507,10 +508,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("cast unreachable",
             \\fn f() -> i32 {
    -        \\    i32(return 1)
    +        \\    return i32(return 1);
             \\}
             \\export fn entry() { _ = f(); }
    -    , ".tmp_source.zig:2:8: error: unreachable code");
    +    , ".tmp_source.zig:2:15: error: unreachable code");
     
         cases.add("invalid builtin fn",
             \\fn f() -> @bogus(foo) {
    @@ -533,7 +534,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("struct init syntax for array",
             \\const foo = []u16{.x = 1024,};
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax");
     
         cases.add("type variables must be constant",
    @@ -576,7 +577,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    }
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch");
     
         cases.add("switch expression - duplicate enumeration prong",
    @@ -596,7 +597,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    }
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:13:15: error: duplicate switch value",
           ".tmp_source.zig:10:15: note: other value is here");
     
    @@ -618,7 +619,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    }
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:13:15: error: duplicate switch value",
           ".tmp_source.zig:10:15: note: other value is here");
     
    @@ -641,20 +642,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\        0 => {},
             \\    }
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         ,
             ".tmp_source.zig:2:5: error: switch must handle all possibilities");
     
         cases.add("switch expression - duplicate or overlapping integer value",
             \\fn foo(x: u8) -> u8 {
    -        \\    switch (x) {
    +        \\    return switch (x) {
             \\        0 ... 100 => u8(0),
             \\        101 ... 200 => 1,
             \\        201, 203 ... 207 => 2,
             \\        206 ... 255 => 3,
    -        \\    }
    +        \\    };
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         ,
             ".tmp_source.zig:6:9: error: duplicate switch value",
             ".tmp_source.zig:5:14: note: previous value is here");
    @@ -666,14 +667,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    }
             \\}
             \\const y: u8 = 100;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         ,
             ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'");
     
         cases.add("global variable initializer must be constant expression",
             \\extern fn foo() -> i32;
             \\const x = foo();
    -        \\export fn entry() -> i32 { x }
    +        \\export fn entry() -> i32 { return x; }
         , ".tmp_source.zig:2:11: error: unable to evaluate constant expression");
     
         cases.add("array concatenation with wrong type",
    @@ -681,38 +682,38 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const derp = usize(1234);
             \\const a = derp ++ "foo";
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
         , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'");
     
         cases.add("non compile time array concatenation",
             \\fn f() -> []u8 {
    -        \\    s ++ "foo"
    +        \\    return s ++ "foo";
             \\}
             \\var s: [10]u8 = undefined;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    -    , ".tmp_source.zig:2:5: error: unable to evaluate constant expression");
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
    +    , ".tmp_source.zig:2:12: error: unable to evaluate constant expression");
     
         cases.add("@cImport with bogus include",
             \\const c = @cImport(@cInclude("bogus.h"));
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(c.bogo)); }
         , ".tmp_source.zig:1:11: error: C import failed",
                      ".h:1:10: note: 'bogus.h' file not found");
     
         cases.add("address of number literal",
             \\const x = 3;
             \\const y = &x;
    -        \\fn foo() -> &const i32 { y }
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    -    , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'");
    +        \\fn foo() -> &const i32 { return y; }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
    +    , ".tmp_source.zig:3:33: error: expected type '&const i32', found '&const (integer literal)'");
     
         cases.add("integer overflow error",
             \\const x : u8 = 300;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
         , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'");
     
         cases.add("incompatible number literals",
             \\const x = 2 == 2.0;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
         , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'");
     
         cases.add("missing function call param",
    @@ -738,32 +739,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    const result = members[index]();
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0");
     
         cases.add("missing function name and param name",
             \\fn () {}
             \\fn f(i32) {}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         ,
                 ".tmp_source.zig:1:1: error: missing function name",
                 ".tmp_source.zig:2:6: error: missing parameter name");
     
         cases.add("wrong function type",
             \\const fns = []fn(){ a, b, c };
    -        \\fn a() -> i32 {0}
    -        \\fn b() -> i32 {1}
    -        \\fn c() -> i32 {2}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
    +        \\fn a() -> i32 {return 0;}
    +        \\fn b() -> i32 {return 1;}
    +        \\fn c() -> i32 {return 2;}
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); }
         , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'");
     
         cases.add("extern function pointer mismatch",
             \\const fns = [](fn(i32)->i32){ a, b, c };
    -        \\pub fn a(x: i32) -> i32 {x + 0}
    -        \\pub fn b(x: i32) -> i32 {x + 1}
    -        \\export fn c(x: i32) -> i32 {x + 2}
    +        \\pub fn a(x: i32) -> i32 {return x + 0;}
    +        \\pub fn b(x: i32) -> i32 {return x + 1;}
    +        \\export fn c(x: i32) -> i32 {return x + 2;}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(fns)); }
         , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'");
     
     
    @@ -771,14 +772,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const x : f64 = 1.0;
             \\const y : f32 = x;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'");
     
     
         cases.add("colliding invalid top level functions",
             \\fn func() -> bogus {}
             \\fn func() -> bogus {}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(func)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(func)); }
         ,
                 ".tmp_source.zig:2:1: error: redefinition of 'func'",
                 ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'");
    @@ -786,7 +787,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("bogus compile var",
             \\const x = @import("builtin").bogus;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
         , ".tmp_source.zig:1:29: error: no member named 'bogus' in '");
     
     
    @@ -795,11 +796,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    y: [get()]u8,
             \\};
             \\var global_var: usize = 1;
    -        \\fn get() -> usize { global_var }
    +        \\fn get() -> usize { return global_var; }
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(Foo)); }
         ,
    -            ".tmp_source.zig:5:21: error: unable to evaluate constant expression",
    +            ".tmp_source.zig:5:28: error: unable to evaluate constant expression",
                 ".tmp_source.zig:2:12: note: called from here",
                 ".tmp_source.zig:2:8: note: called from here");
     
    @@ -810,7 +811,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\};
             \\const x = Foo {.field = 1} + Foo {.field = 2};
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
         , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'");
     
     
    @@ -820,10 +821,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const int_x = u32(1) / u32(0);
             \\const float_x = f32(1.0) / f32(0.0);
             \\
    -        \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) }
    -        \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) }
    -        \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) }
    -        \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) }
    +        \\export fn entry1() -> usize { return @sizeOf(@typeOf(lit_int_x)); }
    +        \\export fn entry2() -> usize { return @sizeOf(@typeOf(lit_float_x)); }
    +        \\export fn entry3() -> usize { return @sizeOf(@typeOf(int_x)); }
    +        \\export fn entry4() -> usize { return @sizeOf(@typeOf(float_x)); }
         ,
                 ".tmp_source.zig:1:21: error: division by zero is undefined",
                 ".tmp_source.zig:2:25: error: division by zero is undefined",
    @@ -835,14 +836,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const foo = "a
             \\b";
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:1:13: error: newline not allowed in string literal");
     
         cases.add("invalid comparison for function pointers",
             \\fn foo() {}
             \\const invalid = foo > foo;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(invalid)); }
         , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'");
     
         cases.add("generic function instance with non-constant expression",
    @@ -851,13 +852,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return foo(a, b);
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(test1)); }
         , ".tmp_source.zig:3:16: error: unable to evaluate constant expression");
     
         cases.add("assign null to non-nullable pointer",
             \\const a: &u8 = null;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
         , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'");
     
         cases.add("indexing an array of size zero",
    @@ -870,18 +871,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         cases.add("compile time division by zero",
             \\const y = foo(0);
             \\fn foo(x: u32) -> u32 {
    -        \\    1 / x
    +        \\    return 1 / x;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         ,
    -            ".tmp_source.zig:3:7: error: division by zero is undefined",
    +            ".tmp_source.zig:3:14: error: division by zero is undefined",
                 ".tmp_source.zig:1:14: note: called from here");
     
         cases.add("branch on undefined value",
             \\const x = if (undefined) true else false;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(x)); }
         , ".tmp_source.zig:1:15: error: use of undefined value");
     
     
    @@ -891,7 +892,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return fibbonaci(x - 1) + fibbonaci(x - 2);
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(seventh_fib_number)); }
         ,
                 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
                 ".tmp_source.zig:3:21: note: called from here");
    @@ -899,7 +900,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         cases.add("@embedFile with bogus file",
             \\const resource = @embedFile("bogus.txt");
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(resource)); }
         , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'");
     
         cases.add("non-const expression in struct literal outside function",
    @@ -909,7 +910,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const a = Foo {.x = get_it()};
             \\extern fn get_it() -> i32;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
         , ".tmp_source.zig:4:21: error: unable to evaluate constant expression");
     
         cases.add("non-const expression function call with struct return value outside function",
    @@ -919,11 +920,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const a = get_it();
             \\fn get_it() -> Foo {
             \\    global_side_effect = true;
    -        \\    Foo {.x = 13}
    +        \\    return Foo {.x = 13};
             \\}
             \\var global_side_effect = false;
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
         ,
                 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
                 ".tmp_source.zig:4:17: note: called from here");
    @@ -939,21 +940,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("illegal comparison of types",
             \\fn bad_eql_1(a: []u8, b: []u8) -> bool {
    -        \\    a == b
    +        \\    return a == b;
             \\}
             \\const EnumWithData = union(enum) {
             \\    One: void,
             \\    Two: i32,
             \\};
             \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
    -        \\    *a == *b
    +        \\    return *a == *b;
             \\}
             \\
    -        \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }
    -        \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }
    +        \\export fn entry1() -> usize { return @sizeOf(@typeOf(bad_eql_1)); }
    +        \\export fn entry2() -> usize { return @sizeOf(@typeOf(bad_eql_2)); }
         ,
    -            ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'",
    -            ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'");
    +            ".tmp_source.zig:2:14: error: operator not allowed for type '[]u8'",
    +            ".tmp_source.zig:9:15: error: operator not allowed for type 'EnumWithData'");
     
         cases.add("non-const switch number literal",
             \\export fn foo() {
    @@ -964,7 +965,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    };
             \\}
             \\fn bar() -> i32 {
    -        \\    2
    +        \\    return 2;
             \\}
         , ".tmp_source.zig:2:15: error: unable to infer expression type");
     
    @@ -987,56 +988,56 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         cases.add("negation overflow in function evaluation",
             \\const y = neg(-128);
             \\fn neg(x: i8) -> i8 {
    -        \\    -x
    +        \\    return -x;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         ,
    -            ".tmp_source.zig:3:5: error: negation caused overflow",
    +            ".tmp_source.zig:3:12: error: negation caused overflow",
                 ".tmp_source.zig:1:14: note: called from here");
     
         cases.add("add overflow in function evaluation",
             \\const y = add(65530, 10);
             \\fn add(a: u16, b: u16) -> u16 {
    -        \\    a + b
    +        \\    return a + b;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         ,
    -            ".tmp_source.zig:3:7: error: operation caused overflow",
    +            ".tmp_source.zig:3:14: error: operation caused overflow",
                 ".tmp_source.zig:1:14: note: called from here");
     
     
         cases.add("sub overflow in function evaluation",
             \\const y = sub(10, 20);
             \\fn sub(a: u16, b: u16) -> u16 {
    -        \\    a - b
    +        \\    return a - b;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         ,
    -            ".tmp_source.zig:3:7: error: operation caused overflow",
    +            ".tmp_source.zig:3:14: error: operation caused overflow",
                 ".tmp_source.zig:1:14: note: called from here");
     
         cases.add("mul overflow in function evaluation",
             \\const y = mul(300, 6000);
             \\fn mul(a: u16, b: u16) -> u16 {
    -        \\    a * b
    +        \\    return a * b;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(y)); }
         ,
    -            ".tmp_source.zig:3:7: error: operation caused overflow",
    +            ".tmp_source.zig:3:14: error: operation caused overflow",
                 ".tmp_source.zig:1:14: note: called from here");
     
         cases.add("truncate sign mismatch",
             \\fn f() -> i8 {
             \\    const x: u32 = 10;
    -        \\    @truncate(i8, x)
    +        \\    return @truncate(i8, x);
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    -    , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'");
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
    +    , ".tmp_source.zig:3:26: error: expected signed integer type, found 'u32'");
     
         cases.add("%return in function with non error return type",
             \\export fn f() {
    @@ -1067,16 +1068,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("export function with comptime parameter",
             \\export fn foo(comptime x: i32, y: i32) -> i32{
    -        \\    x + y
    +        \\    return x + y;
             \\}
         , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
     
         cases.add("extern function with comptime parameter",
             \\extern fn foo(comptime x: i32, y: i32) -> i32;
             \\fn f() -> i32 {
    -        \\    foo(1, 2)
    +        \\    return foo(1, 2);
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
     
         cases.add("convert fixed size array to slice with invalid size",
    @@ -1090,15 +1091,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\var a: u32 = 0;
             \\pub fn List(comptime T: type) -> type {
             \\    a += 1;
    -        \\    SmallList(T, 8)
    +        \\    return SmallList(T, 8);
             \\}
             \\
             \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
    -        \\    struct {
    +        \\    return struct {
             \\        items: []T,
             \\        length: usize,
             \\        prealloc_items: [STATIC_SIZE]T,
    -        \\    }
    +        \\    };
             \\}
             \\
             \\export fn function_with_return_type_type() {
    @@ -1113,7 +1114,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\fn f(m: []const u8) {
             \\    m.copy(u8, self[0..], m);
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'");
     
         cases.add("wrong number of arguments for method fn call",
    @@ -1124,7 +1125,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\
             \\    foo.method(1, 2);
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(f)); }
         , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3");
     
         cases.add("assign through constant pointer",
    @@ -1149,7 +1150,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\fn foo(blah: []u8) {
             \\    for (blah) { }
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:2:5: error: for loop expression missing element parameter");
     
         cases.add("misspelled type with pointer only reference",
    @@ -1182,7 +1183,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} };
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'");
     
         cases.add("method call with first arg type primitive",
    @@ -1190,9 +1191,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    x: i32,
             \\
             \\    fn init(x: i32) -> Foo {
    -        \\        Foo {
    +        \\        return Foo {
             \\            .x = x,
    -        \\        }
    +        \\        };
             \\    }
             \\};
             \\
    @@ -1209,10 +1210,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    allocator: &Allocator,
             \\
             \\    pub fn init(allocator: &Allocator) -> List {
    -        \\        List {
    +        \\        return List {
             \\            .len = 0,
             \\            .allocator = allocator,
    -        \\        }
    +        \\        };
             \\    }
             \\};
             \\
    @@ -1235,10 +1236,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
             \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(block_aligned_stuff)); }
         , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'");
     
    -    cases.addCase({
    +    cases.addCase(x: {
             const tc = cases.create("multiple files with private function error",
                 \\const foo = @import("foo.zig");
                 \\
    @@ -1253,14 +1254,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
                 \\fn privateFunction() { }
             );
     
    -        tc
    +        break :x tc;
         });
     
         cases.add("container init with non-type",
             \\const zero: i32 = 0;
             \\const a = zero{1};
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(a)); }
         , ".tmp_source.zig:2:11: error: expected type, found 'i32'");
     
         cases.add("assign to constant field",
    @@ -1288,22 +1289,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return 0;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(testTrickyDefer)); }
         , ".tmp_source.zig:4:11: error: cannot return from defer expression");
     
         cases.add("attempt to access var args out of bounds",
             \\fn add(args: ...) -> i32 {
    -        \\    args[0] + args[1]
    +        \\    return args[0] + args[1];
             \\}
             \\
             \\fn foo() -> i32 {
    -        \\    add(i32(1234))
    +        \\    return add(i32(1234));
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         ,
    -            ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1",
    -            ".tmp_source.zig:6:8: note: called from here");
    +            ".tmp_source.zig:2:26: error: index 1 outside argument list of size 1",
    +            ".tmp_source.zig:6:15: note: called from here");
     
         cases.add("pass integer literal to var args",
             \\fn add(args: ...) -> i32 {
    @@ -1315,11 +1316,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\}
             \\
             \\fn bar() -> i32 {
    -        \\    add(1, 2, 3, 4)
    +        \\    return add(1, 2, 3, 4);
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) }
    -    , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime");
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(bar)); }
    +    , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime");
     
         cases.add("assign too big number to u16",
             \\export fn foo() {
    @@ -1329,12 +1330,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("global variable alignment non power of 2",
             \\const some_data: [100]u8 align(3) = undefined;
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(some_data)); }
         , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2");
     
         cases.add("function alignment non power of 2",
             \\extern fn foo() align(3);
    -        \\export fn entry() { foo() }
    +        \\export fn entry() { return foo(); }
         , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2");
     
         cases.add("compile log",
    @@ -1369,7 +1370,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return *x;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'");
     
         cases.add("referring to a struct that is invalid",
    @@ -1405,14 +1406,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    bar();
             \\}
    -        \\fn bar() -> i32 { 0 }
    +        \\fn bar() -> i32 { return 0; }
         , ".tmp_source.zig:2:8: error: expression value is ignored");
     
         cases.add("ignored assert-err-ok return value",
             \\export fn foo() {
             \\    %%bar();
             \\}
    -        \\fn bar() -> %i32 { 0 }
    +        \\fn bar() -> %i32 { return 0; }
         , ".tmp_source.zig:2:5: error: expression value is ignored");
     
         cases.add("ignored statement value",
    @@ -1439,11 +1440,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\}
         , ".tmp_source.zig:2:12: error: expression value is ignored");
     
    -    cases.add("ignored defered statement value",
    +    cases.add("ignored defered function call",
             \\export fn foo() {
             \\    defer bar();
             \\}
    -        \\fn bar() -> %i32 { 0 }
    +        \\fn bar() -> %i32 { return 0; }
         , ".tmp_source.zig:2:14: error: expression value is ignored");
     
         cases.add("dereference an array",
    @@ -1454,7 +1455,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return (*out)[0..1];
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(pass)); }
         , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'");
     
         cases.add("pass const ptr to mutable ptr fn",
    @@ -1467,10 +1468,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    return true;
             \\}
             \\
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'");
     
    -    cases.addCase({
    +    cases.addCase(x: {
             const tc = cases.create("export collision",
                 \\const foo = @import("foo.zig");
                 \\
    @@ -1486,13 +1487,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
                 \\pub const baz = 1234;
             );
     
    -        tc
    +        break :x tc;
         });
     
         cases.add("pass non-copyable type by value to function",
             \\const Point = struct { x: i32, y: i32, };
             \\fn foo(p: Point) { }
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value");
     
         cases.add("implicit cast from array to mutable slice",
    @@ -1515,7 +1516,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\fn foo(e: error) -> u2 {
             \\    return u2(e);
             \\}
    -        \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
    +        \\export fn entry() -> usize { return @sizeOf(@typeOf(foo)); }
         , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'");
     
         cases.add("asm at compile time",
    @@ -1665,17 +1666,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("inner struct member shadowing outer struct member",
             \\fn A() -> type {
    -        \\    struct {
    +        \\    return struct {
             \\        b: B(),
             \\
             \\        const Self = this;
             \\
             \\        fn B() -> type {
    -        \\            struct {
    +        \\            return struct {
             \\                const Self = this;
    -        \\            }
    +        \\            };
             \\        }
    -        \\    }
    +        \\    };
             \\}
             \\comptime {
             \\    assert(A().B().Self != A().Self);
    @@ -1691,7 +1692,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) {}
             \\}
    -        \\fn bar() -> ?i32 { 1 }
    +        \\fn bar() -> ?i32 { return 1; }
         ,
             ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'");
     
    @@ -1699,7 +1700,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) {}
             \\}
    -        \\fn bar() -> %i32 { 1 }
    +        \\fn bar() -> %i32 { return 1; }
         ,
             ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'");
     
    @@ -1707,7 +1708,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) |x| {}
             \\}
    -        \\fn bar() -> bool { true }
    +        \\fn bar() -> bool { return true; }
         ,
             ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'");
     
    @@ -1715,7 +1716,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) |x| {}
             \\}
    -        \\fn bar() -> %i32 { 1 }
    +        \\fn bar() -> %i32 { return 1; }
         ,
             ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'");
     
    @@ -1723,7 +1724,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) |x| {} else |err| {}
             \\}
    -        \\fn bar() -> bool { true }
    +        \\fn bar() -> bool { return true; }
         ,
             ".tmp_source.zig:2:15: error: expected error union type, found 'bool'");
     
    @@ -1731,7 +1732,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\export fn foo() {
             \\    while (bar()) |x| {} else |err| {}
             \\}
    -        \\fn bar() -> ?i32 { 1 }
    +        \\fn bar() -> ?i32 { return 1; }
         ,
             ".tmp_source.zig:2:15: error: expected error union type, found '?i32'");
     
    @@ -1762,17 +1763,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("signed integer division",
             \\export fn foo(a: i32, b: i32) -> i32 {
    -        \\    a / b
    +        \\    return a / b;
             \\}
         ,
    -        ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact");
    +        ".tmp_source.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact");
     
         cases.add("signed integer remainder division",
             \\export fn foo(a: i32, b: i32) -> i32 {
    -        \\    a % b
    +        \\    return a % b;
             \\}
         ,
    -        ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod");
    +        ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod");
     
         cases.add("cast negative value to unsigned integer",
             \\comptime {
    @@ -1922,17 +1923,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("explicit cast float literal to integer when there is a fraction component",
             \\export fn entry() -> i32 {
    -        \\    i32(12.34)
    +        \\    return i32(12.34);
             \\}
         ,
    -        ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'");
    +        ".tmp_source.zig:2:16: error: fractional component prevents float value 12.340000 from being casted to type 'i32'");
     
         cases.add("non pointer given to @ptrToInt",
             \\export fn entry(x: i32) -> usize {
    -        \\    @ptrToInt(x)
    +        \\    return @ptrToInt(x);
             \\}
         ,
    -        ".tmp_source.zig:2:15: error: expected pointer, found 'i32'");
    +        ".tmp_source.zig:2:22: error: expected pointer, found 'i32'");
     
         cases.add("@shlExact shifts out 1 bits",
             \\comptime {
    @@ -2028,7 +2029,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     
         cases.add("@alignCast expects pointer or slice",
             \\export fn entry() {
    -        \\    @alignCast(4, u32(3))
    +        \\    @alignCast(4, u32(3));
             \\}
         ,
             ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'");
    @@ -2040,7 +2041,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) {
             \\    if (ptr() != answer) unreachable;
             \\}
    -        \\fn alignedSmall() align(4) -> i32 { 1234 }
    +        \\fn alignedSmall() align(4) -> i32 { return 1234; }
         ,
             ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'");
     
    @@ -2206,17 +2207,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\const Mode = @import("builtin").Mode;
             \\
             \\fn Free(comptime filename: []const u8) -> TestCase {
    -        \\    TestCase {
    +        \\    return TestCase {
             \\        .filename = filename,
             \\        .problem_type = ProblemType.Free,
    -        \\    }
    +        \\    };
             \\}
             \\
             \\fn LibC(comptime filename: []const u8) -> TestCase {
    -        \\    TestCase {
    +        \\    return TestCase {
             \\        .filename = filename,
             \\        .problem_type = ProblemType.LinkLibC,
    -        \\    }
    +        \\    };
             \\}
             \\
             \\const TestCase = struct {
    @@ -2374,9 +2375,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\pub fn MemoryPool(comptime T: type) -> type {
             \\    const free_list_t = @compileError("aoeu");
             \\
    -        \\    struct {
    +        \\    return struct {
             \\        free_list: free_list_t,
    -        \\    }
    +        \\    };
             \\}
             \\
             \\export fn entry() {
    @@ -2651,7 +2652,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    C: bool,
             \\};
             \\export fn entry() {
    -        \\    var a = Payload { .A = { 1234 } };
    +        \\    var a = Payload { .A = 1234 };
             \\}
         ,
             ".tmp_source.zig:6:29: error: extern union does not support enum tag type");
    @@ -2668,7 +2669,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    C: bool,
             \\};
             \\export fn entry() {
    -        \\    var a = Payload { .A = { 1234 } };
    +        \\    var a = Payload { .A = 1234 };
             \\}
         ,
             ".tmp_source.zig:6:29: error: packed union does not support enum tag type");
    @@ -2680,7 +2681,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
             \\    C: bool,
             \\};
             \\export fn entry() {
    -        \\    const a = Payload { .A = { 1234 } };
    +        \\    const a = Payload { .A = 1234 };
             \\    foo(a);
             \\}
             \\fn foo(a: &const Payload) {
    diff --git a/test/debug_safety.zig b/test/debug_safety.zig
    index 36f8d020c3..58ebf838b0 100644
    --- a/test/debug_safety.zig
    +++ b/test/debug_safety.zig
    @@ -19,7 +19,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    baz(bar(a));
             \\}
             \\fn bar(a: []const i32) -> i32 {
    -        \\    a[4]
    +        \\    return a[4];
             \\}
             \\fn baz(a: i32) { }
         );
    @@ -34,7 +34,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn add(a: u16, b: u16) -> u16 {
    -        \\    a + b
    +        \\    return a + b;
             \\}
         );
     
    @@ -48,7 +48,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn sub(a: u16, b: u16) -> u16 {
    -        \\    a - b
    +        \\    return a - b;
             \\}
         );
     
    @@ -62,7 +62,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn mul(a: u16, b: u16) -> u16 {
    -        \\    a * b
    +        \\    return a * b;
             \\}
         );
     
    @@ -76,7 +76,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 32767) return error.Whatever;
             \\}
             \\fn neg(a: i16) -> i16 {
    -        \\    -a
    +        \\    return -a;
             \\}
         );
     
    @@ -90,7 +90,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 32767) return error.Whatever;
             \\}
             \\fn div(a: i16, b: i16) -> i16 {
    -        \\    @divTrunc(a, b)
    +        \\    return @divTrunc(a, b);
             \\}
         );
     
    @@ -104,7 +104,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn shl(a: i16, b: u4) -> i16 {
    -        \\    @shlExact(a, b)
    +        \\    return @shlExact(a, b);
             \\}
         );
     
    @@ -118,7 +118,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn shl(a: u16, b: u4) -> u16 {
    -        \\    @shlExact(a, b)
    +        \\    return @shlExact(a, b);
             \\}
         );
     
    @@ -132,7 +132,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn shr(a: i16, b: u4) -> i16 {
    -        \\    @shrExact(a, b)
    +        \\    return @shrExact(a, b);
             \\}
         );
     
    @@ -146,7 +146,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn shr(a: u16, b: u4) -> u16 {
    -        \\    @shrExact(a, b)
    +        \\    return @shrExact(a, b);
             \\}
         );
     
    @@ -159,7 +159,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    const x = div0(999, 0);
             \\}
             \\fn div0(a: i32, b: i32) -> i32 {
    -        \\    @divTrunc(a, b)
    +        \\    return @divTrunc(a, b);
             \\}
         );
     
    @@ -173,7 +173,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn divExact(a: i32, b: i32) -> i32 {
    -        \\    @divExact(a, b)
    +        \\    return @divExact(a, b);
             \\}
         );
     
    @@ -187,7 +187,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x.len == 0) return error.Whatever;
             \\}
             \\fn widenSlice(slice: []align(1) const u8) -> []align(1) const i32 {
    -        \\    ([]align(1) const i32)(slice)
    +        \\    return ([]align(1) const i32)(slice);
             \\}
         );
     
    @@ -201,7 +201,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn shorten_cast(x: i32) -> i8 {
    -        \\    i8(x)
    +        \\    return i8(x);
             \\}
         );
     
    @@ -215,7 +215,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
             \\    if (x == 0) return error.Whatever;
             \\}
             \\fn unsigned_cast(x: i32) -> u32 {
    -        \\    u32(x)
    +        \\    return u32(x);
             \\}
         );
     
    diff --git a/test/standalone/pkg_import/pkg.zig b/test/standalone/pkg_import/pkg.zig
    index a051497fdb..52ca884937 100644
    --- a/test/standalone/pkg_import/pkg.zig
    +++ b/test/standalone/pkg_import/pkg.zig
    @@ -1 +1 @@
    -pub fn add(a: i32, b: i32) -> i32 { a + b }
    +pub fn add(a: i32, b: i32) -> i32 { return a + b; }
    diff --git a/test/tests.zig b/test/tests.zig
    index a5eb9d4db9..a184045125 100644
    --- a/test/tests.zig
    +++ b/test/tests.zig
    @@ -284,7 +284,7 @@ pub const CompareOutputContext = struct {
                         warn("Process {} terminated unexpectedly\n", full_exe_path);
                         return error.TestFailed;
                     },
    -            };
    +            }
     
     
                 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
    @@ -615,7 +615,7 @@ pub const CompileErrorContext = struct {
                         warn("Process {} terminated unexpectedly\n", b.zig_exe);
                         return error.TestFailed;
                     },
    -            };
    +            }
     
     
                 const stdout = stdout_buf.toSliceConst();
    @@ -891,7 +891,7 @@ pub const TranslateCContext = struct {
                         warn("Compilation terminated unexpectedly\n");
                         return error.TestFailed;
                     },
    -            };
    +            }
     
                 const stdout = stdout_buf.toSliceConst();
                 const stderr = stderr_buf.toSliceConst();
    diff --git a/test/translate_c.zig b/test/translate_c.zig
    index 4f545139e7..cdf900c8b2 100644
    --- a/test/translate_c.zig
    +++ b/test/translate_c.zig
    @@ -203,13 +203,13 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\pub extern var fn_ptr: ?extern fn();
         ,
             \\pub inline fn foo() {
    -        \\    (??fn_ptr)()
    +        \\    return (??fn_ptr)();
             \\}
         ,
             \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
         ,
             \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 {
    -        \\    (??fn_ptr2)(arg0, arg1)
    +        \\    return (??fn_ptr2)(arg0, arg1);
             \\}
         );
     
    @@ -475,10 +475,10 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\pub export fn max(a: c_int) {
             \\    var b: c_int;
             \\    var c: c_int;
    -        \\    c = {
    +        \\    c = x: {
             \\        const _tmp = a;
             \\        b = _tmp;
    -        \\        _tmp
    +        \\        break :x _tmp;
             \\    };
             \\}
         );
    @@ -613,9 +613,9 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\}
         ,
             \\pub export fn foo() -> c_int {
    -        \\    return {
    +        \\    return x: {
             \\        _ = 1;
    -        \\        2
    +        \\        break :x 2;
             \\    };
             \\}
         );
    @@ -645,45 +645,45 @@ pub fn addCases(cases: &tests.TranslateCContext) {
         ,
             \\pub export fn foo() {
             \\    var a: c_int = 0;
    -        \\    a += {
    +        \\    a += x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) + 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a -= {
    +        \\    a -= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) - 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a *= {
    +        \\    a *= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) * 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a &= {
    +        \\    a &= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) & 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a |= {
    +        \\    a |= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) | 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a ^= {
    +        \\    a ^= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) ^ 1);
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a >>= @import("std").math.Log2Int(c_int)({
    +        \\    a >>= @import("std").math.Log2Int(c_int)(x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    });
    -        \\    a <<= @import("std").math.Log2Int(c_int)({
    +        \\    a <<= @import("std").math.Log2Int(c_int)(x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    });
             \\}
         );
    @@ -703,45 +703,45 @@ pub fn addCases(cases: &tests.TranslateCContext) {
         ,
             \\pub export fn foo() {
             \\    var a: c_uint = c_uint(0);
    -        \\    a +%= {
    +        \\    a +%= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) +% c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a -%= {
    +        \\    a -%= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) -% c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a *%= {
    +        \\    a *%= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) *% c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a &= {
    +        \\    a &= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) & c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a |= {
    +        \\    a |= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) | c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a ^= {
    +        \\    a ^= x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) ^ c_uint(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    a >>= @import("std").math.Log2Int(c_uint)({
    +        \\    a >>= @import("std").math.Log2Int(c_uint)(x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    });
    -        \\    a <<= @import("std").math.Log2Int(c_uint)({
    +        \\    a <<= @import("std").math.Log2Int(c_uint)(x: {
             \\        const _ref = &a;
             \\        (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    });
             \\}
         );
    @@ -778,29 +778,29 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\    i -= 1;
             \\    u +%= 1;
             \\    u -%= 1;
    -        \\    i = {
    +        \\    i = x: {
             \\        const _ref = &i;
             \\        const _tmp = *_ref;
             \\        (*_ref) += 1;
    -        \\        _tmp
    +        \\        break :x _tmp;
             \\    };
    -        \\    i = {
    +        \\    i = x: {
             \\        const _ref = &i;
             \\        const _tmp = *_ref;
             \\        (*_ref) -= 1;
    -        \\        _tmp
    +        \\        break :x _tmp;
             \\    };
    -        \\    u = {
    +        \\    u = x: {
             \\        const _ref = &u;
             \\        const _tmp = *_ref;
             \\        (*_ref) +%= 1;
    -        \\        _tmp
    +        \\        break :x _tmp;
             \\    };
    -        \\    u = {
    +        \\    u = x: {
             \\        const _ref = &u;
             \\        const _tmp = *_ref;
             \\        (*_ref) -%= 1;
    -        \\        _tmp
    +        \\        break :x _tmp;
             \\    };
             \\}
         );
    @@ -826,25 +826,25 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\    i -= 1;
             \\    u +%= 1;
             \\    u -%= 1;
    -        \\    i = {
    +        \\    i = x: {
             \\        const _ref = &i;
             \\        (*_ref) += 1;
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    i = {
    +        \\    i = x: {
             \\        const _ref = &i;
             \\        (*_ref) -= 1;
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    u = {
    +        \\    u = x: {
             \\        const _ref = &u;
             \\        (*_ref) +%= 1;
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
    -        \\    u = {
    +        \\    u = x: {
             \\        const _ref = &u;
             \\        (*_ref) -%= 1;
    -        \\        *_ref
    +        \\        break :x *_ref;
             \\    };
             \\}
         );
    @@ -1037,7 +1037,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
             \\pub const glClearPFN = PFNGLCLEARPROC;
         ,
             \\pub inline fn glClearUnion(arg0: GLbitfield) {
    -        \\    (??glProcs.gl.Clear)(arg0)
    +        \\    return (??glProcs.gl.Clear)(arg0);
             \\}
         ,
             \\pub const OpenGLProcs = union_OpenGLProcs;
    -- 
    cgit v1.2.3