translate-c: prevent name clashing of macros declared after locals
This commit is contained in:
parent
9298b9a4aa
commit
ec09b9e5f0
@ -83,6 +83,7 @@ const Scope = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given the desired name, return a name that does not shadow anything from outer scopes.
|
/// Given the desired name, return a name that does not shadow anything from outer scopes.
|
||||||
|
/// Inserts the returned name into the scope.
|
||||||
fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
|
fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
|
||||||
var proposed_name = name;
|
var proposed_name = name;
|
||||||
while (scope.contains(proposed_name)) {
|
while (scope.contains(proposed_name)) {
|
||||||
@ -136,15 +137,37 @@ const Scope = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn localContains(scope: *Root, name: []const u8) bool {
|
/// Given the desired name, return a name that does not shadow anything from outer scopes.
|
||||||
return scope.sym_table.contains(name) or
|
/// Inserts the returned name into the scope.
|
||||||
|
/// Will allow `name` to be one of the preprocessed decl or macro names, but will not
|
||||||
|
/// choose a mangled name that matches one of those.
|
||||||
|
fn makeMangledName(scope: *Root, name: []const u8) ![]const u8 {
|
||||||
|
if (!scope.containsNow(name)) {
|
||||||
|
_ = try scope.context.global_names.put(name, {});
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
var proposed_name = name;
|
||||||
|
while (scope.contains(proposed_name)) {
|
||||||
|
proposed_name = try std.fmt.allocPrint(scope.context.a(), "{}_{}", .{
|
||||||
|
name,
|
||||||
|
scope.context.getMangle(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ = try scope.context.global_names.put(proposed_name, {});
|
||||||
|
return proposed_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the global scope contains this name, without looking into the "future", e.g.
|
||||||
|
/// ignore the preprocessed decl and macro names.
|
||||||
|
fn containsNow(scope: *Root, name: []const u8) bool {
|
||||||
|
return isZigPrimitiveType(name) or
|
||||||
|
scope.sym_table.contains(name) or
|
||||||
scope.macro_table.contains(name);
|
scope.macro_table.contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the global scope contains the name, includes all decls that haven't been translated yet.
|
||||||
fn contains(scope: *Root, name: []const u8) bool {
|
fn contains(scope: *Root, name: []const u8) bool {
|
||||||
return scope.localContains(name) or
|
return scope.containsNow(name) or scope.context.global_names.contains(name);
|
||||||
isZigPrimitiveType(name) or
|
|
||||||
scope.context.global_names.contains(name);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -308,9 +331,7 @@ pub fn translate(
|
|||||||
};
|
};
|
||||||
context.global_scope.* = Scope.Root.init(&context);
|
context.global_scope.* = Scope.Root.init(&context);
|
||||||
|
|
||||||
if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorNamesOnlyC)) {
|
try prepopulateGlobalNameTable(ast_unit, &context);
|
||||||
return context.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
|
if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
|
||||||
return context.err;
|
return context.err;
|
||||||
@ -339,6 +360,29 @@ pub fn translate(
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepopulateGlobalNameTable(ast_unit: *ZigClangASTUnit, c: *Context) !void {
|
||||||
|
if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, declVisitorNamesOnlyC)) {
|
||||||
|
return c.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO if we see #undef, delete it from the table
|
||||||
|
var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(ast_unit);
|
||||||
|
const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(ast_unit);
|
||||||
|
|
||||||
|
while (it.I != it_end.I) : (it.I += 1) {
|
||||||
|
const entity = ZigClangPreprocessingRecord_iterator_deref(it);
|
||||||
|
switch (ZigClangPreprocessedEntity_getKind(entity)) {
|
||||||
|
.MacroDefinitionKind => {
|
||||||
|
const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity);
|
||||||
|
const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro);
|
||||||
|
const name = try c.str(raw_name);
|
||||||
|
_ = try c.global_names.put(name, {});
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
|
extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
|
||||||
const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
|
const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
|
||||||
declVisitorNamesOnly(c, decl) catch |err| {
|
declVisitorNamesOnly(c, decl) catch |err| {
|
||||||
@ -4272,7 +4316,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
|||||||
var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
|
var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
|
||||||
const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
|
const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
|
||||||
var tok_list = ctok.TokenList.init(c.a());
|
var tok_list = ctok.TokenList.init(c.a());
|
||||||
const scope = &c.global_scope.base;
|
const scope = c.global_scope;
|
||||||
|
|
||||||
while (it.I != it_end.I) : (it.I += 1) {
|
while (it.I != it_end.I) : (it.I += 1) {
|
||||||
const entity = ZigClangPreprocessingRecord_iterator_deref(it);
|
const entity = ZigClangPreprocessingRecord_iterator_deref(it);
|
||||||
@ -4285,14 +4329,8 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
|||||||
|
|
||||||
const name = try c.str(raw_name);
|
const name = try c.str(raw_name);
|
||||||
|
|
||||||
// TODO https://github.com/ziglang/zig/issues/3756
|
|
||||||
// TODO https://github.com/ziglang/zig/issues/1802
|
|
||||||
const checked_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name;
|
|
||||||
if (scope.contains(checked_name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
|
const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
|
||||||
ctok.tokenizeCMacro(c, begin_loc, checked_name, &tok_list, begin_c) catch |err| switch (err) {
|
ctok.tokenizeCMacro(c, begin_loc, name, &tok_list, begin_c) catch |err| switch (err) {
|
||||||
error.OutOfMemory => |e| return e,
|
error.OutOfMemory => |e| return e,
|
||||||
else => {
|
else => {
|
||||||
continue;
|
continue;
|
||||||
@ -4307,7 +4345,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
|||||||
.Identifier => {
|
.Identifier => {
|
||||||
// if it equals itself, ignore. for example, from stdio.h:
|
// if it equals itself, ignore. for example, from stdio.h:
|
||||||
// #define stdin stdin
|
// #define stdin stdin
|
||||||
if (mem.eql(u8, checked_name, next.bytes)) {
|
if (mem.eql(u8, name, next.bytes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -4318,15 +4356,19 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
|||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO https://github.com/ziglang/zig/issues/3756
|
||||||
|
// TODO https://github.com/ziglang/zig/issues/1802
|
||||||
|
const mangled_name = try scope.makeMangledName(name);
|
||||||
const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {
|
const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {
|
||||||
_ = tok_it.next();
|
_ = tok_it.next();
|
||||||
break :blk true;
|
break :blk true;
|
||||||
} else false;
|
} else false;
|
||||||
|
|
||||||
(if (macro_fn)
|
(if (macro_fn)
|
||||||
transMacroFnDefine(c, &tok_it, checked_name, begin_loc)
|
transMacroFnDefine(c, &tok_it, mangled_name, begin_loc)
|
||||||
else
|
else
|
||||||
transMacroDefine(c, &tok_it, checked_name, begin_loc)) catch |err| switch (err) {
|
transMacroDefine(c, &tok_it, mangled_name, begin_loc)) catch |err| switch (err) {
|
||||||
error.ParseError => continue,
|
error.ParseError => continue,
|
||||||
error.OutOfMemory => |e| return e,
|
error.OutOfMemory => |e| return e,
|
||||||
};
|
};
|
||||||
|
@ -2288,4 +2288,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\}
|
\\}
|
||||||
\\pub export var bar: c_int = 4;
|
\\pub export var bar: c_int = 4;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cases.add("arg name aliasing macro which comes after",
|
||||||
|
\\int foo(int bar) {
|
||||||
|
\\ bar = 2;
|
||||||
|
\\}
|
||||||
|
\\#define bar 4
|
||||||
|
, &[_][]const u8{
|
||||||
|
\\pub export fn foo(arg_bar_1: c_int) c_int {
|
||||||
|
\\ var bar_1 = arg_bar_1;
|
||||||
|
\\ bar_1 = 2;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
\\pub const bar = 4;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user