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.
This commit is contained in:
Evan Haas
2021-07-07 00:11:02 -07:00
committed by Veikka Tuominen
parent c905056562
commit 3e67ef5c9f
5 changed files with 18 additions and 9 deletions

View File

@@ -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' => {},

View File

@@ -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;
}
}

View File

@@ -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)});

View File

@@ -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;
\\}
, "");
}

View File

@@ -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;
});
}