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(
439439 return ast.render(gpa, context.global_scope.nodes.items);
440440}
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
442460fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
443461 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
444462 return error.OutOfMemory;
......@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
455473 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
456474 const raw_name = macro.getName_getNameStart();
457475 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 }
459480 },
460481 else => {},
461482 }
......@@ -5446,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi
54465467 }
54475468}
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
54495480fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54505481 // TODO if we see #undef, delete it from the table
54515482 var it = unit.getLocalPreprocessingEntities_begin();
......@@ -5462,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54625493 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
54635494 const raw_name = macro.getName_getNameStart();
54645495 const begin_loc = macro.getSourceRange_getBegin();
5465 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54665496
54675497 const name = try c.str(raw_name);
54685498 if (scope.containsNow(name)) {
54695499 continue;
54705500 }
54715501
5472 const begin_c = c.source_manager.getCharacterData(begin_loc);
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];
5502 const source = getMacroText(unit, c, macro);
54765503
5477 try tokenizeMacro(slice, &tok_list);
5504 try tokenizeMacro(source, &tok_list);
54785505
54795506 var macro_ctx = MacroCtx{
5480 .source = slice,
5507 .source = source,
54815508 .list = tok_list.items,
54825509 .name = name,
54835510 .loc = begin_loc,
......@@ -5490,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54905517 // if it equals itself, ignore. for example, from stdio.h:
54915518 // #define stdin stdin
54925519 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]));
54945522 continue;
54955523 }
54965524 },
test/standalone.zig+1
......@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
99 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/6025
1010 cases.add("test/standalone/issue_9693/main.zig");
1111 }
12 cases.add("test/standalone/issue_12471/main.zig");
1213 cases.add("test/standalone/guess_number/main.zig");
1314 cases.add("test/standalone/main_return_error/error_u8.zig");
1415 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}