authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-01 19:23:46-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-01 19:23:46-05:00
logec09b9e5f0d2f9f603210c1d493b0e563aba13a5
tree42260e0ad8a6ddb8f3aa8a9dc424c8be02b1e4df
parent9298b9a4aab74524a3f4167fe127a35ea8ba13e8
signature Commit is signed but in an unrecognized format.

translate-c: prevent name clashing of macros declared after locals


2 files changed, 75 insertions(+), 19 deletions(-)

src-self-hosted/translate_c.zig+61-19
......@@ -83,6 +83,7 @@ const Scope = struct {
8383 }
8484
8585 /// Given the desired name, return a name that does not shadow anything from outer scopes.
86 /// Inserts the returned name into the scope.
8687 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
8788 var proposed_name = name;
8889 while (scope.contains(proposed_name)) {
......@@ -136,15 +137,37 @@ const Scope = struct {
136137 };
137138 }
138139
139 fn localContains(scope: *Root, name: []const u8) bool {
140 return scope.sym_table.contains(name) or
140 /// Given the desired name, return a name that does not shadow anything from outer scopes.
141 /// Inserts the returned name into the scope.
142 /// Will allow `name` to be one of the preprocessed decl or macro names, but will not
143 /// choose a mangled name that matches one of those.
144 fn makeMangledName(scope: *Root, name: []const u8) ![]const u8 {
145 if (!scope.containsNow(name)) {
146 _ = try scope.context.global_names.put(name, {});
147 return name;
148 }
149 var proposed_name = name;
150 while (scope.contains(proposed_name)) {
151 proposed_name = try std.fmt.allocPrint(scope.context.a(), "{}_{}", .{
152 name,
153 scope.context.getMangle(),
154 });
155 }
156 _ = try scope.context.global_names.put(proposed_name, {});
157 return proposed_name;
158 }
159
160 /// Check if the global scope contains this name, without looking into the "future", e.g.
161 /// ignore the preprocessed decl and macro names.
162 fn containsNow(scope: *Root, name: []const u8) bool {
163 return isZigPrimitiveType(name) or
164 scope.sym_table.contains(name) or
141165 scope.macro_table.contains(name);
142166 }
143167
168 /// Check if the global scope contains the name, includes all decls that haven't been translated yet.
144169 fn contains(scope: *Root, name: []const u8) bool {
145 return scope.localContains(name) or
146 isZigPrimitiveType(name) or
147 scope.context.global_names.contains(name);
170 return scope.containsNow(name) or scope.context.global_names.contains(name);
148171 }
149172 };
150173
......@@ -308,9 +331,7 @@ pub fn translate(
308331 };
309332 context.global_scope.* = Scope.Root.init(&context);
310333
311 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorNamesOnlyC)) {
312 return context.err;
313 }
334 try prepopulateGlobalNameTable(ast_unit, &context);
314335
315336 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
316337 return context.err;
......@@ -339,6 +360,29 @@ pub fn translate(
339360 return tree;
340361}
341362
363fn prepopulateGlobalNameTable(ast_unit: *ZigClangASTUnit, c: *Context) !void {
364 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, declVisitorNamesOnlyC)) {
365 return c.err;
366 }
367
368 // TODO if we see #undef, delete it from the table
369 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(ast_unit);
370 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(ast_unit);
371
372 while (it.I != it_end.I) : (it.I += 1) {
373 const entity = ZigClangPreprocessingRecord_iterator_deref(it);
374 switch (ZigClangPreprocessedEntity_getKind(entity)) {
375 .MacroDefinitionKind => {
376 const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity);
377 const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro);
378 const name = try c.str(raw_name);
379 _ = try c.global_names.put(name, {});
380 },
381 else => {},
382 }
383 }
384}
385
342386extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
343387 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
344388 declVisitorNamesOnly(c, decl) catch |err| {
......@@ -4272,7 +4316,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
42724316 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
42734317 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
42744318 var tok_list = ctok.TokenList.init(c.a());
4275 const scope = &c.global_scope.base;
4319 const scope = c.global_scope;
42764320
42774321 while (it.I != it_end.I) : (it.I += 1) {
42784322 const entity = ZigClangPreprocessingRecord_iterator_deref(it);
......@@ -4285,14 +4329,8 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
42854329
42864330 const name = try c.str(raw_name);
42874331
4288 // TODO https://github.com/ziglang/zig/issues/3756
4289 // TODO https://github.com/ziglang/zig/issues/1802
4290 const checked_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name;
4291 if (scope.contains(checked_name)) {
4292 continue;
4293 }
42944332 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
4295 ctok.tokenizeCMacro(c, begin_loc, checked_name, &tok_list, begin_c) catch |err| switch (err) {
4333 ctok.tokenizeCMacro(c, begin_loc, name, &tok_list, begin_c) catch |err| switch (err) {
42964334 error.OutOfMemory => |e| return e,
42974335 else => {
42984336 continue;
......@@ -4307,7 +4345,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
43074345 .Identifier => {
43084346 // if it equals itself, ignore. for example, from stdio.h:
43094347 // #define stdin stdin
4310 if (mem.eql(u8, checked_name, next.bytes)) {
4348 if (mem.eql(u8, name, next.bytes)) {
43114349 continue;
43124350 }
43134351 },
......@@ -4318,15 +4356,19 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
43184356 },
43194357 else => {},
43204358 }
4359
4360 // TODO https://github.com/ziglang/zig/issues/3756
4361 // TODO https://github.com/ziglang/zig/issues/1802
4362 const mangled_name = try scope.makeMangledName(name);
43214363 const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {
43224364 _ = tok_it.next();
43234365 break :blk true;
43244366 } else false;
43254367
43264368 (if (macro_fn)
4327 transMacroFnDefine(c, &tok_it, checked_name, begin_loc)
4369 transMacroFnDefine(c, &tok_it, mangled_name, begin_loc)
43284370 else
4329 transMacroDefine(c, &tok_it, checked_name, begin_loc)) catch |err| switch (err) {
4371 transMacroDefine(c, &tok_it, mangled_name, begin_loc)) catch |err| switch (err) {
43304372 error.ParseError => continue,
43314373 error.OutOfMemory => |e| return e,
43324374 };
test/translate_c.zig+14
......@@ -2288,4 +2288,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22882288 \\}
22892289 \\pub export var bar: c_int = 4;
22902290 });
2291
2292 cases.add("arg name aliasing macro which comes after",
2293 \\int foo(int bar) {
2294 \\ bar = 2;
2295 \\}
2296 \\#define bar 4
2297 , &[_][]const u8{
2298 \\pub export fn foo(arg_bar_1: c_int) c_int {
2299 \\ var bar_1 = arg_bar_1;
2300 \\ bar_1 = 2;
2301 \\}
2302 ,
2303 \\pub const bar = 4;
2304 });
22912305}