| ... | @@ -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 | } |
| 441 | | 441 | |
| | 442 | /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) |
| | 443 | /// Macros of this form will not be translated. |
| | 444 | fn 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 | |
| 442 | fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { | 460 | fn 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 | } |
| 5448 | | 5469 | |
| | 5470 | fn 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 | |
| 5449 | fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { | 5480 | fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5450 | // TODO if we see #undef, delete it from the table | 5481 | // 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); | | |
| 5466 | | 5496 | |
| 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 | } |
| 5471 | | 5501 | |
| 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]; | | |
| 5476 | | 5503 | |
| 5477 | try tokenizeMacro(slice, &tok_list); | 5504 | try tokenizeMacro(source, &tok_list); |
| 5478 | | 5505 | |
| 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 stdin | 5518 | // #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 | }, |