mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
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
This commit is contained in:
parent
d6bb9af18d
commit
bcaa9df5b4
@ -439,6 +439,24 @@ pub fn translate(
|
||||
return ast.render(gpa, context.global_scope.nodes.items);
|
||||
}
|
||||
|
||||
/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
|
||||
/// Macros of this form will not be translated.
|
||||
fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {
|
||||
const source = getMacroText(unit, c, macro);
|
||||
var tokenizer = std.c.Tokenizer{
|
||||
.buffer = source,
|
||||
};
|
||||
const name_tok = tokenizer.next();
|
||||
const name = source[name_tok.start..name_tok.end];
|
||||
|
||||
const first_tok = tokenizer.next();
|
||||
// We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
|
||||
// the tokenizer.
|
||||
// In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)
|
||||
if (first_tok.id == .Eof) return false;
|
||||
return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
|
||||
}
|
||||
|
||||
fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
|
||||
if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
|
||||
return error.OutOfMemory;
|
||||
@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
|
||||
const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
|
||||
const raw_name = macro.getName_getNameStart();
|
||||
const name = try c.str(raw_name);
|
||||
try c.global_names.put(c.gpa, name, {});
|
||||
|
||||
if (!isSelfDefinedMacro(ast_unit, c, macro)) {
|
||||
try c.global_names.put(c.gpa, name, {});
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -5446,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi
|
||||
}
|
||||
}
|
||||
|
||||
fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 {
|
||||
const begin_loc = macro.getSourceRange_getBegin();
|
||||
const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
|
||||
|
||||
const begin_c = c.source_manager.getCharacterData(begin_loc);
|
||||
const end_c = c.source_manager.getCharacterData(end_loc);
|
||||
const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
|
||||
return begin_c[0..slice_len];
|
||||
}
|
||||
|
||||
fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
|
||||
// TODO if we see #undef, delete it from the table
|
||||
var it = unit.getLocalPreprocessingEntities_begin();
|
||||
@ -5462,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
|
||||
const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
|
||||
const raw_name = macro.getName_getNameStart();
|
||||
const begin_loc = macro.getSourceRange_getBegin();
|
||||
const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
|
||||
|
||||
const name = try c.str(raw_name);
|
||||
if (scope.containsNow(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const begin_c = c.source_manager.getCharacterData(begin_loc);
|
||||
const end_c = c.source_manager.getCharacterData(end_loc);
|
||||
const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
|
||||
const slice = begin_c[0..slice_len];
|
||||
const source = getMacroText(unit, c, macro);
|
||||
|
||||
try tokenizeMacro(slice, &tok_list);
|
||||
try tokenizeMacro(source, &tok_list);
|
||||
|
||||
var macro_ctx = MacroCtx{
|
||||
.source = slice,
|
||||
.source = source,
|
||||
.list = tok_list.items,
|
||||
.name = name,
|
||||
.loc = begin_loc,
|
||||
@ -5490,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
|
||||
// if it equals itself, ignore. for example, from stdio.h:
|
||||
// #define stdin stdin
|
||||
const tok = macro_ctx.list[1];
|
||||
if (mem.eql(u8, name, slice[tok.start..tok.end])) {
|
||||
if (mem.eql(u8, name, source[tok.start..tok.end])) {
|
||||
assert(!c.global_names.contains(source[tok.start..tok.end]));
|
||||
continue;
|
||||
}
|
||||
},
|
||||
|
||||
@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/6025
|
||||
cases.add("test/standalone/issue_9693/main.zig");
|
||||
}
|
||||
cases.add("test/standalone/issue_12471/main.zig");
|
||||
cases.add("test/standalone/guess_number/main.zig");
|
||||
cases.add("test/standalone/main_return_error/error_u8.zig");
|
||||
cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
|
||||
|
||||
12
test/standalone/issue_12471/main.zig
Normal file
12
test/standalone/issue_12471/main.zig
Normal file
@ -0,0 +1,12 @@
|
||||
const c = @cImport({
|
||||
@cDefine("FOO", "FOO");
|
||||
@cDefine("BAR", "FOO");
|
||||
|
||||
@cDefine("BAZ", "QUX");
|
||||
@cDefine("QUX", "QUX");
|
||||
});
|
||||
|
||||
pub fn main() u8 {
|
||||
_ = c;
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user