authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2022-08-21 10:58:08-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-26 11:24:57+03:00
logbcaa9df5b42747577dcb529a99f6da6d69e09309
tree3e3a96c92a7db9c2da04d8a1e09d1eae8c106965
parentd6bb9af18da6f1e6d4e62a111c69a58c91b21a7e

translate-c: Don't add self-defined macros to global name table

A self-defined macro is one of the form `#define FOO FOO` Those types of macros have never been translated; this change will cause any macros which refer to them to be translated as `@compileError` instead of referring to a non-existent identifier. Closes #12471

3 files changed, 50 insertions(+), 9 deletions(-)

src/translate_c.zig+37-9
...@@ -439,6 +439,24 @@ pub fn translate(...@@ -439,6 +439,24 @@ pub fn translate(
439 return ast.render(gpa, context.global_scope.nodes.items);439 return ast.render(gpa, context.global_scope.nodes.items);
440}440}
441441
442/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
443/// Macros of this form will not be translated.
444fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {
445 const source = getMacroText(unit, c, macro);
446 var tokenizer = std.c.Tokenizer{
447 .buffer = source,
448 };
449 const name_tok = tokenizer.next();
450 const name = source[name_tok.start..name_tok.end];
451
452 const first_tok = tokenizer.next();
453 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
454 // the tokenizer.
455 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)
456 if (first_tok.id == .Eof) return false;
457 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
458}
459
442fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {460fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
443 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {461 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
444 return error.OutOfMemory;462 return error.OutOfMemory;
...@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {...@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
455 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);473 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
456 const raw_name = macro.getName_getNameStart();474 const raw_name = macro.getName_getNameStart();
457 const name = try c.str(raw_name);475 const name = try c.str(raw_name);
458 try c.global_names.put(c.gpa, name, {});476
477 if (!isSelfDefinedMacro(ast_unit, c, macro)) {
478 try c.global_names.put(c.gpa, name, {});
479 }
459 },480 },
460 else => {},481 else => {},
461 }482 }
...@@ -5446,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi...@@ -5446,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi
5446 }5467 }
5447}5468}
54485469
5470fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 {
5471 const begin_loc = macro.getSourceRange_getBegin();
5472 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
5473
5474 const begin_c = c.source_manager.getCharacterData(begin_loc);
5475 const end_c = c.source_manager.getCharacterData(end_loc);
5476 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
5477 return begin_c[0..slice_len];
5478}
5479
5449fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {5480fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5450 // TODO if we see #undef, delete it from the table5481 // TODO if we see #undef, delete it from the table
5451 var it = unit.getLocalPreprocessingEntities_begin();5482 var it = unit.getLocalPreprocessingEntities_begin();
...@@ -5462,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5462,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5462 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);5493 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
5463 const raw_name = macro.getName_getNameStart();5494 const raw_name = macro.getName_getNameStart();
5464 const begin_loc = macro.getSourceRange_getBegin();5495 const begin_loc = macro.getSourceRange_getBegin();
5465 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54665496
5467 const name = try c.str(raw_name);5497 const name = try c.str(raw_name);
5468 if (scope.containsNow(name)) {5498 if (scope.containsNow(name)) {
5469 continue;5499 continue;
5470 }5500 }
54715501
5472 const begin_c = c.source_manager.getCharacterData(begin_loc);5502 const source = getMacroText(unit, c, macro);
5473 const end_c = c.source_manager.getCharacterData(end_loc);
5474 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
5475 const slice = begin_c[0..slice_len];
54765503
5477 try tokenizeMacro(slice, &tok_list);5504 try tokenizeMacro(source, &tok_list);
54785505
5479 var macro_ctx = MacroCtx{5506 var macro_ctx = MacroCtx{
5480 .source = slice,5507 .source = source,
5481 .list = tok_list.items,5508 .list = tok_list.items,
5482 .name = name,5509 .name = name,
5483 .loc = begin_loc,5510 .loc = begin_loc,
...@@ -5490,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5490,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5490 // if it equals itself, ignore. for example, from stdio.h:5517 // if it equals itself, ignore. for example, from stdio.h:
5491 // #define stdin stdin5518 // #define stdin stdin
5492 const tok = macro_ctx.list[1];5519 const tok = macro_ctx.list[1];
5493 if (mem.eql(u8, name, slice[tok.start..tok.end])) {5520 if (mem.eql(u8, name, source[tok.start..tok.end])) {
5521 assert(!c.global_names.contains(source[tok.start..tok.end]));
5494 continue;5522 continue;
5495 }5523 }
5496 },5524 },
test/standalone.zig+1
...@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
9 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/60259 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/6025
10 cases.add("test/standalone/issue_9693/main.zig");10 cases.add("test/standalone/issue_9693/main.zig");
11 }11 }
12 cases.add("test/standalone/issue_12471/main.zig");
12 cases.add("test/standalone/guess_number/main.zig");13 cases.add("test/standalone/guess_number/main.zig");
13 cases.add("test/standalone/main_return_error/error_u8.zig");14 cases.add("test/standalone/main_return_error/error_u8.zig");
14 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");15 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
test/standalone/issue_12471/main.zig created+12
...@@ -0,0 +1,12 @@
1const c = @cImport({
2 @cDefine("FOO", "FOO");
3 @cDefine("BAR", "FOO");
4
5 @cDefine("BAZ", "QUX");
6 @cDefine("QUX", "QUX");
7});
8
9pub fn main() u8 {
10 _ = c;
11 return 0;
12}