Commit 3e67ef5c9f

Evan Haas <evan@lagerdata.com>
2021-07-07 09:11:02
translate-c: Handle underscore when used as an identifier
Use `@` syntax to escape `_` when used as an identifier. Remove the stage1 astgen prohibition against assigning from `_` Note: there a few stage1 bugs preventing `_` from being used as an identifier for a local variable or function parameter; these will be fixed by stage2. They are unlikely to arise in real C code since identifiers starting with underscore are reserved for the implementation.
1 parent c905056
Changed files (5)
lib/std/zig/fmt.zig
@@ -23,6 +23,7 @@ pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
 }
 
 pub fn isValidId(bytes: []const u8) bool {
+    if (mem.eql(u8, bytes, "_")) return false;
     for (bytes) |c, i| {
         switch (c) {
             '_', 'a'...'z', 'A'...'Z' => {},
src/stage1/astgen.cpp
@@ -3821,9 +3821,6 @@ static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode
             const_instruction->value->special = ConstValSpecialStatic;
             const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard;
             return &const_instruction->base;
-        } else {
-            add_node_error(ag->codegen, node, buf_sprintf("`_` may only be used to assign things to"));
-            return ag->codegen->invalid_inst_src;
         }
     }
 
src/translate_c.zig
@@ -4951,10 +4951,6 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
     const scope = &c.global_scope.base;
 
     const init_node = try parseCExpr(c, m, scope);
-    if (init_node.castTag(.identifier)) |ident_node| {
-        if (mem.eql(u8, "_", ident_node.data))
-            return m.fail(c, "unable to translate C expr: illegal identifier _", .{});
-    }
     const last = m.next().?;
     if (last != .Eof and last != .Nl)
         return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
test/run_translated_c.zig
@@ -1647,4 +1647,16 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\   if (a != 1) abort();
         \\}
     , "");
+
+    cases.add("Underscore identifiers",
+        \\#include <stdlib.h>
+        \\int _ = 10;
+        \\typedef struct { int _; } S;
+        \\int main(void) {
+        \\    if (_ != 10) abort();
+        \\    S foo = { ._ = _ };
+        \\    if (foo._ != _) abort();
+        \\    return 0;
+        \\}
+    , "");
 }
test/translate_c.zig
@@ -3616,9 +3616,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("Don't allow underscore identifier in macros",
+    cases.add("Use @ syntax for bare underscore identifier in macro or public symbol",
         \\#define FOO _
+        \\int _ = 42;
     , &[_][]const u8{
-        \\pub const FOO = @compileError("unable to translate C expr: illegal identifier _");
+        \\pub const FOO = @"_";
+        ,
+        \\pub export var @"_": c_int = 42;
     });
 }