Commit b3a6faf13e

Andrew Kelley <superjoe30@gmail.com>
2018-01-24 05:08:09
replace %defer with errdefer
See #632 now we have 1 less sigil
1 parent ad2527d
doc/docgen.zig
@@ -318,7 +318,7 @@ const Action = enum {
 
 fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc {
     var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);
-    %defer urls.deinit();
+    errdefer urls.deinit();
 
     var header_stack_size: usize = 0;
     var last_action = Action.Open;
@@ -399,7 +399,7 @@ fn genToc(allocator: &mem.Allocator, tokenizer: &Tokenizer) -> %Toc {
                     }
                 } else if (mem.eql(u8, tag_name, "see_also")) {
                     var list = std.ArrayList(SeeAlsoItem).init(allocator);
-                    %defer list.deinit();
+                    errdefer list.deinit();
 
                     while (true) {
                         const see_also_tok = tokenizer.next();
doc/langref.html.in
@@ -2533,7 +2533,7 @@ test "defer unwinding" {
     deferUnwindExample();
 }
 
-// The %defer keyword is similar to defer, but will only execute if the
+// The errdefer keyword is similar to defer, but will only execute if the
 // scope returns with an error.
 //
 // This is especially useful in allowing a function to clean up properly
@@ -2547,7 +2547,7 @@ fn deferErrorExample(is_error: bool) -> %void {
         warn("end of function\n");
     }
 
-    %defer {
+    errdefer {
         warn("encountered an error!\n");
     }
 
@@ -2556,7 +2556,7 @@ fn deferErrorExample(is_error: bool) -> %void {
     }
 }
 
-test "%defer unwinding" {
+test "errdefer unwinding" {
     _ = deferErrorExample(false);
     _ = deferErrorExample(true);
 }
@@ -2922,7 +2922,7 @@ fn doAThing(str: []u8) {
       {#code_end#}
       <p>
       The other component to error handling is defer statements.
-      In addition to an unconditional <code>defer</code>, Zig has <code>%defer</code>,
+      In addition to an unconditional <code>defer</code>, Zig has <code>errdefer</code>,
       which evaluates the deferred expression on block exit path if and only if
       the function returned with an error from the block.
       </p>
@@ -2934,7 +2934,7 @@ fn createFoo(param: i32) -> %Foo {
     const foo = try tryToAllocateFoo();
     // now we have allocated foo. we need to free it if the function fails.
     // but we want to return it if the function succeeds.
-    %defer deallocateFoo(foo);
+    errdefer deallocateFoo(foo);
 
     const tmp_buf = allocateTmpBuffer() ?? return error.OutOfMemory;
     // tmp_buf is truly a temporary resource, and we for sure want to clean it up
@@ -2943,7 +2943,7 @@ fn createFoo(param: i32) -> %Foo {
 
     if (param > 1337) return error.InvalidParam;
 
-    // here the %defer will not run since we're returning success from the function.
+    // here the errdefer will not run since we're returning success from the function.
     // but the defer will run!
     return foo;
 }
@@ -5619,7 +5619,7 @@ TryExpression = "try" Expression
 
 BreakExpression = "break" option(":" Symbol) option(Expression)
 
-Defer(body) = option("%") "defer" body
+Defer(body) = ("defer" | "deferror") body
 
 IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
 
src/parser.cpp
@@ -1495,7 +1495,7 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
 }
 
 /*
-Defer(body) = option("%") "defer" body
+Defer(body) = ("defer" | "errdefer") body
 */
 static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
     Token *token = &pc->tokens->at(*token_index);
@@ -1503,15 +1503,10 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
     NodeType node_type;
     ReturnKind kind;
 
-    if (token->id == TokenIdPercent) {
-        Token *next_token = &pc->tokens->at(*token_index + 1);
-        if (next_token->id == TokenIdKeywordDefer) {
-            kind = ReturnKindError;
-            node_type = NodeTypeDefer;
-            *token_index += 2;
-        } else {
-            return nullptr;
-        }
+    if (token->id == TokenIdKeywordErrdefer) {
+        kind = ReturnKindError;
+        node_type = NodeTypeDefer;
+        *token_index += 1;
     } else if (token->id == TokenIdKeywordDefer) {
         kind = ReturnKindUnconditional;
         node_type = NodeTypeDefer;
src/tokenizer.cpp
@@ -118,6 +118,7 @@ static const struct ZigKeyword zig_keywords[] = {
     {"defer", TokenIdKeywordDefer},
     {"else", TokenIdKeywordElse},
     {"enum", TokenIdKeywordEnum},
+    {"errdefer", TokenIdKeywordErrdefer},
     {"error", TokenIdKeywordError},
     {"export", TokenIdKeywordExport},
     {"extern", TokenIdKeywordExtern},
@@ -1514,6 +1515,7 @@ const char * token_name(TokenId id) {
         case TokenIdKeywordDefer: return "defer";
         case TokenIdKeywordElse: return "else";
         case TokenIdKeywordEnum: return "enum";
+        case TokenIdKeywordErrdefer: return "errdefer";
         case TokenIdKeywordError: return "error";
         case TokenIdKeywordExport: return "export";
         case TokenIdKeywordExtern: return "extern";
src/tokenizer.hpp
@@ -57,6 +57,7 @@ enum TokenId {
     TokenIdKeywordDefer,
     TokenIdKeywordElse,
     TokenIdKeywordEnum,
+    TokenIdKeywordErrdefer,
     TokenIdKeywordError,
     TokenIdKeywordExport,
     TokenIdKeywordExtern,
src-self-hosted/main.zig
@@ -371,7 +371,7 @@ pub fn main2() -> %void {
             defer allocator.free(full_cache_dir);
 
             const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix);
-            %defer allocator.free(zig_lib_dir);
+            errdefer allocator.free(zig_lib_dir);
 
             const module = try Module.create(allocator, root_name, zig_root_source_file,
                 Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir);
@@ -587,7 +587,7 @@ fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const
 /// Caller must free result
 fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) -> %[]u8 {
     const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig");
-    %defer allocator.free(test_zig_dir);
+    errdefer allocator.free(test_zig_dir);
 
     const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
     defer allocator.free(test_index_file);
src-self-hosted/module.zig
@@ -113,19 +113,19 @@ pub const Module = struct {
         kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) -> %&Module
     {
         var name_buffer = try Buffer.init(allocator, name);
-        %defer name_buffer.deinit();
+        errdefer name_buffer.deinit();
 
         const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
-        %defer c.LLVMContextDispose(context);
+        errdefer c.LLVMContextDispose(context);
 
         const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
-        %defer c.LLVMDisposeModule(module);
+        errdefer c.LLVMDisposeModule(module);
 
         const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
-        %defer c.LLVMDisposeBuilder(builder);
+        errdefer c.LLVMDisposeBuilder(builder);
 
         const module_ptr = try allocator.create(Module);
-        %defer allocator.destroy(module_ptr);
+        errdefer allocator.destroy(module_ptr);
 
         *module_ptr = Module {
             .allocator = allocator,
@@ -211,13 +211,13 @@ pub const Module = struct {
             try printError("unable to get real path '{}': {}", root_src_path, err);
             return err;
         };
-        %defer self.allocator.free(root_src_real_path);
+        errdefer self.allocator.free(root_src_real_path);
 
         const source_code = io.readFileAllocExtra(root_src_real_path, self.allocator, 3) catch |err| {
             try printError("unable to open '{}': {}", root_src_real_path, err);
             return err;
         };
-        %defer self.allocator.free(source_code);
+        errdefer self.allocator.free(source_code);
         source_code[source_code.len - 3] = '\n';
         source_code[source_code.len - 2] = '\n';
         source_code[source_code.len - 1] = '\n';
src-self-hosted/parser.zig
@@ -127,7 +127,7 @@ pub const Parser = struct {
 
         const root_node = x: {
             const root_node = try self.createRoot();
-            %defer self.allocator.destroy(root_node);
+            errdefer self.allocator.destroy(root_node);
             // This stack append has to succeed for freeAst to work
             try stack.append(State.TopLevel);
             break :x root_node;
@@ -577,7 +577,7 @@ pub const Parser = struct {
 
     fn createRoot(self: &Parser) -> %&ast.NodeRoot {
         const node = try self.allocator.create(ast.NodeRoot);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeRoot {
             .base = ast.Node {.id = ast.Node.Id.Root},
@@ -590,7 +590,7 @@ pub const Parser = struct {
         extern_token: &const ?Token) -> %&ast.NodeVarDecl
     {
         const node = try self.allocator.create(ast.NodeVarDecl);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeVarDecl {
             .base = ast.Node {.id = ast.Node.Id.VarDecl},
@@ -613,7 +613,7 @@ pub const Parser = struct {
         cc_token: &const ?Token, visib_token: &const ?Token, inline_token: &const ?Token) -> %&ast.NodeFnProto
     {
         const node = try self.allocator.create(ast.NodeFnProto);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeFnProto {
             .base = ast.Node {.id = ast.Node.Id.FnProto},
@@ -635,7 +635,7 @@ pub const Parser = struct {
 
     fn createParamDecl(self: &Parser) -> %&ast.NodeParamDecl {
         const node = try self.allocator.create(ast.NodeParamDecl);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeParamDecl {
             .base = ast.Node {.id = ast.Node.Id.ParamDecl},
@@ -650,7 +650,7 @@ pub const Parser = struct {
 
     fn createBlock(self: &Parser, begin_token: &const Token) -> %&ast.NodeBlock {
         const node = try self.allocator.create(ast.NodeBlock);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeBlock {
             .base = ast.Node {.id = ast.Node.Id.Block},
@@ -663,7 +663,7 @@ pub const Parser = struct {
 
     fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) -> %&ast.NodeInfixOp {
         const node = try self.allocator.create(ast.NodeInfixOp);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeInfixOp {
             .base = ast.Node {.id = ast.Node.Id.InfixOp},
@@ -677,7 +677,7 @@ pub const Parser = struct {
 
     fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) -> %&ast.NodePrefixOp {
         const node = try self.allocator.create(ast.NodePrefixOp);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodePrefixOp {
             .base = ast.Node {.id = ast.Node.Id.PrefixOp},
@@ -690,7 +690,7 @@ pub const Parser = struct {
 
     fn createIdentifier(self: &Parser, name_token: &const Token) -> %&ast.NodeIdentifier {
         const node = try self.allocator.create(ast.NodeIdentifier);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeIdentifier {
             .base = ast.Node {.id = ast.Node.Id.Identifier},
@@ -701,7 +701,7 @@ pub const Parser = struct {
 
     fn createIntegerLiteral(self: &Parser, token: &const Token) -> %&ast.NodeIntegerLiteral {
         const node = try self.allocator.create(ast.NodeIntegerLiteral);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeIntegerLiteral {
             .base = ast.Node {.id = ast.Node.Id.IntegerLiteral},
@@ -712,7 +712,7 @@ pub const Parser = struct {
 
     fn createFloatLiteral(self: &Parser, token: &const Token) -> %&ast.NodeFloatLiteral {
         const node = try self.allocator.create(ast.NodeFloatLiteral);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
 
         *node = ast.NodeFloatLiteral {
             .base = ast.Node {.id = ast.Node.Id.FloatLiteral},
@@ -723,14 +723,14 @@ pub const Parser = struct {
 
     fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) -> %&ast.NodeIdentifier {
         const node = try self.createIdentifier(name_token);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
         try dest_ptr.store(&node.base);
         return node;
     }
 
     fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) -> %&ast.NodeParamDecl {
         const node = try self.createParamDecl();
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
         try list.append(&node.base);
         return node;
     }
@@ -740,7 +740,7 @@ pub const Parser = struct {
         inline_token: &const ?Token) -> %&ast.NodeFnProto
     {
         const node = try self.createFnProto(fn_token, extern_token, cc_token, visib_token, inline_token);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
         try list.append(&node.base);
         return node;
     }
@@ -749,7 +749,7 @@ pub const Parser = struct {
         mut_token: &const Token, comptime_token: &const ?Token, extern_token: &const ?Token) -> %&ast.NodeVarDecl
     {
         const node = try self.createVarDecl(visib_token, mut_token, comptime_token, extern_token);
-        %defer self.allocator.destroy(node);
+        errdefer self.allocator.destroy(node);
         try list.append(&node.base);
         return node;
     }
std/debug/index.zig
@@ -248,10 +248,10 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace {
                 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
             };
             st.self_exe_file = try os.openSelfExe();
-            %defer st.self_exe_file.close();
+            errdefer st.self_exe_file.close();
 
             try st.elf.openFile(allocator, &st.self_exe_file);
-            %defer st.elf.close();
+            errdefer st.elf.close();
 
             st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
             st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
@@ -524,7 +524,7 @@ const LineNumberProgram = struct {
                 return error.InvalidDebugInfo;
             } else self.include_dirs[file_entry.dir_index];
             const file_name = try os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
-            %defer self.file_entries.allocator.free(file_name);
+            errdefer self.file_entries.allocator.free(file_name);
             return LineInfo {
                 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
                 .column = self.prev_column,
@@ -563,7 +563,7 @@ fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
 
 fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
     const buf = try global_allocator.alloc(u8, size);
-    %defer global_allocator.free(buf);
+    errdefer global_allocator.free(buf);
     if ((try in_stream.read(buf)) < size) return error.EndOfFile;
     return buf;
 }
std/os/windows/util.zig
@@ -133,7 +133,7 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
         break :x bytes_needed;
     };
     const result = try allocator.alloc(u8, bytes_needed);
-    %defer allocator.free(result);
+    errdefer allocator.free(result);
 
     var it = env_map.iterator();
     var i: usize = 0;
std/os/child_process.zig
@@ -76,7 +76,7 @@ pub const ChildProcess = struct {
     /// On success must call deinit.
     pub fn init(argv: []const []const u8, allocator: &mem.Allocator) -> %&ChildProcess {
         const child = try allocator.create(ChildProcess);
-        %defer allocator.destroy(child);
+        errdefer allocator.destroy(child);
 
         *child = ChildProcess {
             .allocator = allocator,
@@ -336,13 +336,13 @@ pub const ChildProcess = struct {
         install_SIGCHLD_handler();
 
         const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
-        %defer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
+        errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
 
         const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
-        %defer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
+        errdefer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
 
         const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
-        %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
+        errdefer 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)
@@ -367,7 +367,7 @@ pub const ChildProcess = struct {
         // This pipe is used to communicate errors between the time of fork
         // and execve from the child process to the parent process.
         const err_pipe = try makePipe();
-        %defer destroyPipe(err_pipe);
+        errdefer destroyPipe(err_pipe);
 
         block_SIGCHLD();
         const pid_result = posix.fork();
@@ -479,7 +479,7 @@ pub const ChildProcess = struct {
                 g_hChildStd_IN_Rd = null;
             },
         }
-        %defer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr); };
+        errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr); };
 
         var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
         var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
@@ -497,7 +497,7 @@ pub const ChildProcess = struct {
                 g_hChildStd_OUT_Wr = null;
             },
         }
-        %defer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr); };
+        errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr); };
 
         var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
         var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
@@ -515,7 +515,7 @@ pub const ChildProcess = struct {
                 g_hChildStd_ERR_Wr = null;
             },
         }
-        %defer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };
+        errdefer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };
 
         const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
         defer self.allocator.free(cmd_line);
@@ -722,7 +722,7 @@ fn windowsMakePipeIn(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const S
     var rd_h: windows.HANDLE = undefined;
     var wr_h: windows.HANDLE = undefined;
     try windowsMakePipe(&rd_h, &wr_h, sattr);
-    %defer windowsDestroyPipe(rd_h, wr_h);
+    errdefer windowsDestroyPipe(rd_h, wr_h);
     try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
     *rd = rd_h;
     *wr = wr_h;
@@ -732,7 +732,7 @@ fn windowsMakePipeOut(rd: &?windows.HANDLE, wr: &?windows.HANDLE, sattr: &const
     var rd_h: windows.HANDLE = undefined;
     var wr_h: windows.HANDLE = undefined;
     try windowsMakePipe(&rd_h, &wr_h, sattr);
-    %defer windowsDestroyPipe(rd_h, wr_h);
+    errdefer windowsDestroyPipe(rd_h, wr_h);
     try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
     *rd = rd_h;
     *wr = wr_h;
std/os/index.zig
@@ -311,7 +311,7 @@ pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap)
     const envp_count = env_map.count();
     const envp_buf = try allocator.alloc(?&u8, envp_count + 1);
     mem.set(?&u8, envp_buf, null);
-    %defer freeNullDelimitedEnvMap(allocator, envp_buf);
+    errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
     {
         var it = env_map.iterator();
         var i: usize = 0;
@@ -421,7 +421,7 @@ pub var posix_environ_raw: []&u8 = undefined;
 /// Caller must free result when done.
 pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
     var result = BufMap.init(allocator);
-    %defer result.deinit();
+    errdefer result.deinit();
 
     if (is_windows) {
         const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
@@ -489,7 +489,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) -> %[]u8 {
         defer allocator.free(key_with_null);
 
         var buf = try allocator.alloc(u8, 256);
-        %defer allocator.free(buf);
+        errdefer allocator.free(buf);
 
         while (true) {
             const windows_buf_len = try math.cast(windows.DWORD, buf.len);
@@ -521,7 +521,7 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {
     switch (builtin.os) {
         Os.windows => {
             var buf = try allocator.alloc(u8, 256);
-            %defer allocator.free(buf);
+            errdefer allocator.free(buf);
 
             while (true) {
                 const result = windows.GetCurrentDirectoryA(windows.WORD(buf.len), buf.ptr);
@@ -543,7 +543,7 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {
         },
         else => {
             var buf = try allocator.alloc(u8, 1024);
-            %defer allocator.free(buf);
+            errdefer allocator.free(buf);
             while (true) {
                 const err = posix.getErrno(posix.getcwd(buf.ptr, buf.len));
                 if (err == posix.ERANGE) {
@@ -724,7 +724,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
 
     var out_file = try io.File.openWriteMode(tmp_path, mode, allocator);
     defer out_file.close();
-    %defer _ = deleteFile(allocator, tmp_path);
+    errdefer _ = deleteFile(allocator, tmp_path);
 
     var in_file = try io.File.openRead(source_path, allocator);
     defer in_file.close();
@@ -1074,7 +1074,7 @@ pub fn readLink(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
     path_buf[pathname.len] = 0;
 
     var result_buf = try allocator.alloc(u8, 1024);
-    %defer allocator.free(result_buf);
+    errdefer allocator.free(result_buf);
     while (true) {
         const ret_val = posix.readlink(path_buf.ptr, result_buf.ptr, result_buf.len);
         const err = posix.getErrno(ret_val);
@@ -1443,7 +1443,7 @@ pub fn argsAlloc(allocator: &mem.Allocator) -> %[]const []u8 {
     const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
     const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
     const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
-    %defer allocator.free(buf);
+    errdefer allocator.free(buf);
 
     const result_slice_list = ([][]u8)(buf[0..slice_list_bytes]);
     const result_contents = buf[slice_list_bytes..];
@@ -1556,7 +1556,7 @@ pub fn selfExePath(allocator: &mem.Allocator) -> %[]u8 {
         },
         Os.windows => {
             var out_path = try Buffer.initSize(allocator, 0xff);
-            %defer out_path.deinit();
+            errdefer out_path.deinit();
             while (true) {
                 const dword_len = try math.cast(windows.DWORD, out_path.len());
                 const copied_amt = windows.GetModuleFileNameA(null, out_path.ptr(), dword_len);
@@ -1579,7 +1579,7 @@ pub fn selfExePath(allocator: &mem.Allocator) -> %[]u8 {
             const ret1 = c._NSGetExecutablePath(undefined, &u32_len);
             assert(ret1 != 0);
             const bytes = try allocator.alloc(u8, u32_len);
-            %defer allocator.free(bytes);
+            errdefer allocator.free(bytes);
             const ret2 = c._NSGetExecutablePath(bytes.ptr, &u32_len);
             assert(ret2 == 0);
             return bytes;
@@ -1598,13 +1598,13 @@ pub fn selfExeDirPath(allocator: &mem.Allocator) -> %[]u8 {
             // This path cannot be opened, but it's valid for determining the directory
             // the executable was in when it was run.
             const full_exe_path = try readLink(allocator, "/proc/self/exe");
-            %defer allocator.free(full_exe_path);
+            errdefer allocator.free(full_exe_path);
             const dir = path.dirname(full_exe_path);
             return allocator.shrink(u8, full_exe_path, dir.len);
         },
         Os.windows, Os.macosx, Os.ios => {
             const self_exe_path = try selfExePath(allocator);
-            %defer allocator.free(self_exe_path);
+            errdefer allocator.free(self_exe_path);
             const dirname = os.path.dirname(self_exe_path);
             return allocator.shrink(u8, self_exe_path, dirname.len);
         },
std/os/path.zig
@@ -468,7 +468,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) -> %[]u8
         }
         have_drive_kind = parsed_cwd.kind;
     }
-    %defer allocator.free(result);
+    errdefer allocator.free(result);
 
     // Now we know the disk designator to use, if any, and what kind it is. And our result
     // is big enough to append all the paths to.
@@ -551,7 +551,7 @@ pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) -> %[]u8 {
         mem.copy(u8, result, cwd);
         result_index += cwd.len;
     }
-    %defer allocator.free(result);
+    errdefer allocator.free(result);
 
     for (paths[first_index..]) |p, i| {
         var it = mem.split(p, "/");
@@ -943,7 +943,7 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8)
         }
         const up_index_end = up_count * "..\\".len;
         const result = try allocator.alloc(u8, up_index_end + to_rest.len);
-        %defer allocator.free(result);
+        errdefer allocator.free(result);
 
         var result_index: usize = 0;
         while (result_index < up_index_end) {
@@ -993,7 +993,7 @@ pub fn relativePosix(allocator: &Allocator, from: []const u8, to: []const u8) ->
         }
         const up_index_end = up_count * "../".len;
         const result = try allocator.alloc(u8, up_index_end + to_rest.len);
-        %defer allocator.free(result);
+        errdefer allocator.free(result);
 
         var result_index: usize = 0;
         while (result_index < up_index_end) {
@@ -1100,7 +1100,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
             }
             defer os.close(h_file);
             var buf = try allocator.alloc(u8, 256);
-            %defer allocator.free(buf);
+            errdefer allocator.free(buf);
             while (true) {
                 const buf_len = math.cast(windows.DWORD, buf.len) catch return error.NameTooLong;
                 const result = windows.GetFinalPathNameByHandleA(h_file, buf.ptr, buf_len, windows.VOLUME_NAME_DOS);
@@ -1144,7 +1144,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
             defer allocator.free(pathname_buf);
 
             const result_buf = try allocator.alloc(u8, posix.PATH_MAX);
-            %defer allocator.free(result_buf);
+            errdefer allocator.free(result_buf);
 
             mem.copy(u8, pathname_buf, pathname);
             pathname_buf[pathname.len] = 0;
std/buf_map.zig
@@ -30,14 +30,14 @@ pub const BufMap = struct {
     pub fn set(self: &BufMap, key: []const u8, value: []const u8) -> %void {
         if (self.hash_map.get(key)) |entry| {
             const value_copy = try self.copy(value);
-            %defer self.free(value_copy);
+            errdefer self.free(value_copy);
             _ = try self.hash_map.put(key, value_copy);
             self.free(entry.value);
         } else {
             const key_copy = try self.copy(key);
-            %defer self.free(key_copy);
+            errdefer self.free(key_copy);
             const value_copy = try self.copy(value);
-            %defer self.free(value_copy);
+            errdefer self.free(value_copy);
             _ = try self.hash_map.put(key_copy, value_copy);
         }
     }
std/buf_set.zig
@@ -27,7 +27,7 @@ pub const BufSet = struct {
     pub fn put(self: &BufSet, key: []const u8) -> %void {
         if (self.hash_map.get(key) == null) {
             const key_copy = try self.copy(key);
-            %defer self.free(key_copy);
+            errdefer self.free(key_copy);
             _ = try self.hash_map.put(key_copy, {});
         }
     }
std/cstr.zig
@@ -71,7 +71,7 @@ pub const NullTerminated2DArray = struct {
         byte_count += index_size;
 
         const buf = try allocator.alignedAlloc(u8, @alignOf(?&u8), byte_count);
-        %defer allocator.free(buf);
+        errdefer allocator.free(buf);
 
         var write_index = index_size;
         const index_buf = ([]?&u8)(buf);
std/elf.zig
@@ -183,7 +183,7 @@ pub const Elf = struct {
         try elf.in_file.seekTo(elf.section_header_offset);
 
         elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
-        %defer elf.allocator.free(elf.section_headers);
+        errdefer elf.allocator.free(elf.section_headers);
 
         if (elf.is_64) {
             if (sh_entry_size != 64) return error.InvalidFormat;
std/io.zig
@@ -550,7 +550,7 @@ pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len
 
     const size = try file.getEndPos();
     const buf = try allocator.alloc(u8, size + extra_len);
-    %defer allocator.free(buf);
+    errdefer allocator.free(buf);
 
     var adapter = FileInStream.init(&file);
     try adapter.stream.readNoEof(buf[0..size]);
std/mem.zig
@@ -440,7 +440,7 @@ pub fn join(allocator: &Allocator, sep: u8, strings: ...) -> %[]u8 {
     }
 
     const buf = try allocator.alloc(u8, total_strings_len);
-    %defer allocator.free(buf);
+    errdefer allocator.free(buf);
 
     var buf_index: usize = 0;
     comptime var string_i = 0;
test/cases/defer.zig
@@ -8,7 +8,7 @@ error FalseNotAllowed;
 fn runSomeErrorDefers(x: bool) -> %bool {
     index = 0;
     defer {result[index] = 'a'; index += 1;}
-    %defer {result[index] = 'b'; index += 1;}
+    errdefer {result[index] = 'b'; index += 1;}
     defer {result[index] = 'c'; index += 1;}
     return if (x) x else error.FalseNotAllowed;
 }
test/compare_output.zig
@@ -392,7 +392,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
         \\}
     , "before\ndefer2\ndefer1\n");
 
-    cases.add("%defer and it fails",
+    cases.add("errdefer and it fails",
         \\const io = @import("std").io;
         \\pub fn main() -> %void {
         \\    do_test() catch return;
@@ -401,7 +401,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
         \\    const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
         \\    stdout.print("before\n") catch unreachable;
         \\    defer stdout.print("defer1\n") catch unreachable;
-        \\    %defer stdout.print("deferErr\n") catch unreachable;
+        \\    errdefer stdout.print("deferErr\n") catch unreachable;
         \\    try its_gonna_fail();
         \\    defer stdout.print("defer3\n") catch unreachable;
         \\    stdout.print("after\n") catch unreachable;
@@ -412,7 +412,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
         \\}
     , "before\ndeferErr\ndefer1\n");
 
-    cases.add("%defer and it passes",
+    cases.add("errdefer and it passes",
         \\const io = @import("std").io;
         \\pub fn main() -> %void {
         \\    do_test() catch return;
@@ -421,7 +421,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
         \\    const stdout = &(io.FileOutStream.init(&(io.getStdOut() catch unreachable)).stream);
         \\    stdout.print("before\n") catch unreachable;
         \\    defer stdout.print("defer1\n") catch unreachable;
-        \\    %defer stdout.print("deferErr\n") catch unreachable;
+        \\    errdefer stdout.print("deferErr\n") catch unreachable;
         \\    try its_gonna_pass();
         \\    defer stdout.print("defer3\n") catch unreachable;
         \\    stdout.print("after\n") catch unreachable;