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 --- src/parser.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src/parser.cpp') 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 -- cgit v1.2.3 From c627f9ea18b5f194860c6bf3730f3f0407c224f2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 01:19:49 -0500 Subject: wip bring back export keyword --- doc/langref.html.in | 14 ++++--- src/all_types.hpp | 10 ++--- src/analyze.cpp | 29 ++++++++++++- src/ir.cpp | 2 +- src/parser.cpp | 114 ++++++++++++++++++++++++++++++++-------------------- src/tokenizer.cpp | 2 + src/tokenizer.hpp | 1 + 7 files changed, 112 insertions(+), 60 deletions(-) (limited to 'src/parser.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index f302cbec5d..beb113682a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5819,9 +5819,11 @@ TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) ErrorValueDecl = "error" Symbol ";" -GlobalVarDecl = VariableDeclaration ";" +GlobalVarDecl = option("export") VariableDeclaration ";" -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression +LocalVarDecl = option("comptime") VariableDeclaration + +VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression ContainerMember = (ContainerField | FnDef | GlobalVarDecl) @@ -5831,9 +5833,9 @@ UseDecl = "use" Expression ";" ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) -FnDef = option("inline" | "extern") FnProto Block +FnDef = option("inline" | "export") FnProto Block ParamDeclList = "(" list(ParamDecl, ",") ")" @@ -5841,7 +5843,7 @@ ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") Block = "{" many(Statement) option(Expression) "}" -Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" +Statement = Label | LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" Label = Symbol ":" @@ -5947,7 +5949,7 @@ 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 | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr diff --git a/src/all_types.hpp b/src/all_types.hpp index 9256777428..106ccf6471 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -315,12 +315,6 @@ struct TldVar { VariableTableEntry *var; 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 { @@ -428,6 +422,7 @@ struct AstNodeFnProto { AstNode *return_type; bool is_var_args; bool is_extern; + bool is_export; bool is_inline; CallingConvention cc; AstNode *fn_def_node; @@ -485,7 +480,8 @@ struct AstNodeVariableDeclaration { VisibMod visib_mod; Buf *symbol; bool is_const; - bool is_inline; + bool is_comptime; + bool is_export; bool is_extern; // one or both of type and expr will be non null AstNode *type; diff --git a/src/analyze.cpp b/src/analyze.cpp index 84d9b9feaf..470d54ff84 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; + bool extern_abi = fn_proto->is_extern || fn_proto->is_export; fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; } else { fn_type_id->cc = fn_proto->cc; @@ -2675,6 +2675,26 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { + bool is_export = false; + if (tld->id == TldIdVar) { + assert(tld->source_node->type == NodeTypeVariableDeclaration); + is_export = tld->source_node->data.variable_declaration.is_export; + } else if (tld->id == TldIdFn) { + assert(tld->source_node->type == NodeTypeFnProto); + is_export = tld->source_node->data.fn_proto.is_export; + } + if (is_export) { + g->resolve_queue.append(tld); + + auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node); + if (entry) { + AstNode *other_source_node = 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_source_node, buf_sprintf("other symbol here")); + } + } + { auto entry = decls_scope->decl_table.put_unique(tld->name, tld); if (entry) { @@ -3006,6 +3026,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { bool is_const = var_decl->is_const; bool is_extern = var_decl->is_extern; + bool is_export = var_decl->is_export; TypeTableEntry *explicit_type = nullptr; if (var_decl->type) { @@ -3013,8 +3034,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { explicit_type = validate_var_type(g, var_decl->type, proposed_type); } + assert(!is_export || !is_extern); + VarLinkage linkage; - if (is_extern) { + if (is_export) { + linkage = VarLinkageExport; + } else if (is_extern) { linkage = VarLinkageExternal; } else { linkage = VarLinkageInternal; diff --git a/src/ir.cpp b/src/ir.cpp index 81b64a318d..78f7c25dca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5066,7 +5066,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb->exec, scope) || variable_declaration->is_inline); + ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); // we detect IrInstructionIdDeclVar in gen_block to make sure the next node diff --git a/src/parser.cpp b/src/parser.cpp index 07c221e287..a2b06410ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -676,7 +676,7 @@ 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 | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl +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" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -791,13 +791,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo if (container_decl) return container_decl; - if (token->id == TokenIdKeywordExtern) { - *token_index += 1; - AstNode *node = ast_parse_fn_proto(pc, token_index, true, VisibModPrivate); - node->data.fn_proto.is_extern = true; - return node; - } - if (!mandatory) return nullptr; @@ -1534,38 +1527,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) { } /* -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression +VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression */ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory, - VisibMod visib_mod) + VisibMod visib_mod, bool is_comptime, bool is_export) { Token *first_token = &pc->tokens->at(*token_index); Token *var_token; bool is_const; - bool is_comptime; - if (first_token->id == TokenIdKeywordCompTime) { - is_comptime = true; - var_token = &pc->tokens->at(*token_index + 1); - - if (var_token->id == TokenIdKeywordVar) { - is_const = false; - } else if (var_token->id == TokenIdKeywordConst) { - is_const = true; - } else if (mandatory) { - ast_invalid_token_error(pc, var_token); - } else { - return nullptr; - } - - *token_index += 2; - } else if (first_token->id == TokenIdKeywordVar) { - is_comptime = false; + if (first_token->id == TokenIdKeywordVar) { is_const = false; var_token = first_token; *token_index += 1; } else if (first_token->id == TokenIdKeywordConst) { - is_comptime = false; is_const = true; var_token = first_token; *token_index += 1; @@ -1577,7 +1552,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); - node->data.variable_declaration.is_inline = is_comptime; + node->data.variable_declaration.is_comptime = is_comptime; node->data.variable_declaration.is_const = is_const; node->data.variable_declaration.visib_mod = visib_mod; @@ -1620,6 +1595,50 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to return node; } +/* +GlobalVarDecl = option("export") VariableDeclaration ";" +*/ +static AstNode *ast_parse_global_var_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { + Token *first_token = &pc->tokens->at(*token_index); + + bool is_export = false;; + if (first_token->id == TokenIdKeywordExport) { + *token_index += 1; + is_export = true; + } + + AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, is_export); + if (node == nullptr) { + if (is_export) { + *token_index -= 1; + } + return nullptr; + } + return node; +} + +/* +LocalVarDecl = option("comptime") VariableDeclaration +*/ +static AstNode *ast_parse_local_var_decl(ParseContext *pc, size_t *token_index) { + Token *first_token = &pc->tokens->at(*token_index); + + bool is_comptime = false;; + if (first_token->id == TokenIdKeywordCompTime) { + *token_index += 1; + is_comptime = true; + } + + AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate, is_comptime, false); + if (node == nullptr) { + if (is_comptime) { + *token_index -= 1; + } + return nullptr; + } + return node; +} + /* BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression */ @@ -2171,7 +2190,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand for (;;) { AstNode *statement_node = ast_parse_label(pc, token_index, false); if (!statement_node) - statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate); + 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) @@ -2213,13 +2232,14 @@ 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("section" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "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); Token *fn_token; CallingConvention cc; + bool is_extern = false; if (first_token->id == TokenIdKeywordColdCC) { *token_index += 1; fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); @@ -2232,8 +2252,13 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m *token_index += 1; fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); cc = CallingConventionStdcall; + } else if (first_token->id == TokenIdKeywordExtern) { + *token_index += 1; + fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); + cc = CallingConventionC; } else if (first_token->id == TokenIdKeywordFn) { fn_token = first_token; + is_extern = true; *token_index += 1; cc = CallingConventionUnspecified; } else if (mandatory) { @@ -2246,6 +2271,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); node->data.fn_proto.visib_mod = visib_mod; node->data.fn_proto.cc = cc; + node->data.fn_proto.is_extern = is_extern; Token *fn_name = &pc->tokens->at(*token_index); @@ -2286,35 +2312,35 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m } /* -FnDef = option("inline" | "extern") FnProto Block +FnDef = option("inline" | "export") FnProto Block */ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); bool is_inline; - bool is_extern; + bool is_export; if (first_token->id == TokenIdKeywordInline) { *token_index += 1; is_inline = true; - is_extern = false; - } else if (first_token->id == TokenIdKeywordExtern) { + is_export = false; + } else if (first_token->id == TokenIdKeywordExport) { *token_index += 1; - is_extern = true; + is_export = true; is_inline = false; } else { is_inline = false; - is_extern = false; + is_export = false; } AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod); if (!fn_proto) { - if (is_inline || is_extern) { + if (is_inline || is_export) { *token_index -= 1; } return nullptr; } fn_proto->data.fn_proto.is_inline = is_inline; - fn_proto->data.fn_proto.is_extern = is_extern; + fn_proto->data.fn_proto.is_export = is_export; Token *semi_token = &pc->tokens->at(*token_index); if (semi_token->id == TokenIdSemicolon) { @@ -2360,7 +2386,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo return fn_proto_node; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, false); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); @@ -2473,7 +2499,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, continue; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); node->data.container_decl.decls.append(var_decl_node); @@ -2566,7 +2592,7 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) /* TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) +TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) */ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList *top_level_decls) { for (;;) { @@ -2615,7 +2641,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig continue; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); top_level_decls->append(var_decl_node); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a14f709744..9bcc79ede7 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -119,6 +119,7 @@ static const struct ZigKeyword zig_keywords[] = { {"else", TokenIdKeywordElse}, {"enum", TokenIdKeywordEnum}, {"error", TokenIdKeywordError}, + {"export", TokenIdKeywordExport}, {"extern", TokenIdKeywordExtern}, {"false", TokenIdKeywordFalse}, {"fn", TokenIdKeywordFn}, @@ -1518,6 +1519,7 @@ 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"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index b0444b9c3b..58a20adc1a 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -59,6 +59,7 @@ enum TokenId { TokenIdKeywordElse, TokenIdKeywordEnum, TokenIdKeywordError, + TokenIdKeywordExport, TokenIdKeywordExtern, TokenIdKeywordFalse, TokenIdKeywordFn, -- cgit v1.2.3 From 27ba4f0baf5168b2fb8f0dd72b04f528092f075a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 01:49:42 -0500 Subject: export keyword works again --- src/all_types.hpp | 1 - src/analyze.cpp | 33 +++++++++++++++++++++++++++++++++ src/analyze.hpp | 1 + src/ir.cpp | 30 +++--------------------------- src/parser.cpp | 1 + 5 files changed, 38 insertions(+), 28 deletions(-) (limited to 'src/parser.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 106ccf6471..1ec3c809a2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1183,7 +1183,6 @@ enum FnInline { struct FnExport { Buf name; GlobalLinkageId linkage; - AstNode *source_node; }; struct FnTableEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index 470d54ff84..e2df4955da 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2577,6 +2577,34 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { return g->test_fn_type; } +void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc) { + if (ccc) { + if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { + g->have_c_main = true; + g->windows_subsystem_windows = false; + g->windows_subsystem_console = true; + } else if (buf_eql_str(symbol_name, "WinMain") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_winmain = true; + g->windows_subsystem_windows = true; + g->windows_subsystem_console = false; + } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_winmain_crt_startup = true; + } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_dllmain_crt_startup = true; + } + } + FnExport *fn_export = fn_table_entry->export_list.add_one(); + memset(fn_export, 0, sizeof(FnExport)); + buf_init_from_buf(&fn_export->name, symbol_name); + fn_export->linkage = linkage; +} + static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { ImportTableEntry *import = tld_fn->base.import; AstNode *source_node = tld_fn->base.source_node; @@ -2588,6 +2616,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { FnTableEntry *fn_table_entry = create_fn(source_node); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); + if (fn_proto->is_export) { + bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC); + add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc); + } + tld_fn->fn_entry = fn_table_entry; if (fn_table_entry->body_node) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 0e727568c6..6224e64dd5 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -183,5 +183,6 @@ TypeTableEntry *get_align_amt_type(CodeGen *g); PackageTableEntry *new_anonymous_package(void); Buf *const_value_to_buffer(ConstExprValue *const_val); +void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 78f7c25dca..4afc1a2c60 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10504,35 +10504,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi 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; + case CallingConventionStdcall: + add_fn_export(ira->codegen, fn_entry, symbol_name, global_linkage_id, cc == CallingConventionC); + break; } } break; case TypeTableEntryIdStruct: diff --git a/src/parser.cpp b/src/parser.cpp index a2b06410ea..cc337471ba 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1553,6 +1553,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); node->data.variable_declaration.is_comptime = is_comptime; + node->data.variable_declaration.is_export = is_export; node->data.variable_declaration.is_const = is_const; node->data.variable_declaration.visib_mod = visib_mod; -- 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/parser.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/parser.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/parser.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