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 {...@@ -83,6 +83,7 @@ const Scope = struct {
83 }83 }
8484
85 /// Given the desired name, return a name that does not shadow anything from outer scopes.85 /// Given the desired name, return a name that does not shadow anything from outer scopes.
86 /// Inserts the returned name into the scope.
86 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {87 fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 {
87 var proposed_name = name;88 var proposed_name = name;
88 while (scope.contains(proposed_name)) {89 while (scope.contains(proposed_name)) {
...@@ -136,15 +137,37 @@ const Scope = struct {...@@ -136,15 +137,37 @@ const Scope = struct {
136 };137 };
137 }138 }
138139
139 fn localContains(scope: *Root, name: []const u8) bool {140 /// Given the desired name, return a name that does not shadow anything from outer scopes.
140 return scope.sym_table.contains(name) or141 /// 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
141 scope.macro_table.contains(name);165 scope.macro_table.contains(name);
142 }166 }
143167
168 /// Check if the global scope contains the name, includes all decls that haven't been translated yet.
144 fn contains(scope: *Root, name: []const u8) bool {169 fn contains(scope: *Root, name: []const u8) bool {
145 return scope.localContains(name) or170 return scope.containsNow(name) or scope.context.global_names.contains(name);
146 isZigPrimitiveType(name) or
147 scope.context.global_names.contains(name);
148 }171 }
149 };172 };
150173
...@@ -308,9 +331,7 @@ pub fn translate(...@@ -308,9 +331,7 @@ pub fn translate(
308 };331 };
309 context.global_scope.* = Scope.Root.init(&context);332 context.global_scope.* = Scope.Root.init(&context);
310333
311 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorNamesOnlyC)) {334 try prepopulateGlobalNameTable(ast_unit, &context);
312 return context.err;
313 }
314335
315 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {336 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
316 return context.err;337 return context.err;
...@@ -339,6 +360,29 @@ pub fn translate(...@@ -339,6 +360,29 @@ pub fn translate(
339 return tree;360 return tree;
340}361}
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
342extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {386extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool {
343 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));387 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
344 declVisitorNamesOnly(c, decl) catch |err| {388 declVisitorNamesOnly(c, decl) catch |err| {
...@@ -4272,7 +4316,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4272,7 +4316,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4272 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);4316 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
4273 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);4317 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
4274 var tok_list = ctok.TokenList.init(c.a());4318 var tok_list = ctok.TokenList.init(c.a());
4275 const scope = &c.global_scope.base;4319 const scope = c.global_scope;
42764320
4277 while (it.I != it_end.I) : (it.I += 1) {4321 while (it.I != it_end.I) : (it.I += 1) {
4278 const entity = ZigClangPreprocessingRecord_iterator_deref(it);4322 const entity = ZigClangPreprocessingRecord_iterator_deref(it);
...@@ -4285,14 +4329,8 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4285,14 +4329,8 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
42854329
4286 const name = try c.str(raw_name);4330 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 }
4294 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);4332 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) {
4296 error.OutOfMemory => |e| return e,4334 error.OutOfMemory => |e| return e,
4297 else => {4335 else => {
4298 continue;4336 continue;
...@@ -4307,7 +4345,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4307,7 +4345,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4307 .Identifier => {4345 .Identifier => {
4308 // if it equals itself, ignore. for example, from stdio.h:4346 // if it equals itself, ignore. for example, from stdio.h:
4309 // #define stdin stdin4347 // #define stdin stdin
4310 if (mem.eql(u8, checked_name, next.bytes)) {4348 if (mem.eql(u8, name, next.bytes)) {
4311 continue;4349 continue;
4312 }4350 }
4313 },4351 },
...@@ -4318,15 +4356,19 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4318,15 +4356,19 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4318 },4356 },
4319 else => {},4357 else => {},
4320 }4358 }
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);
4321 const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {4363 const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {
4322 _ = tok_it.next();4364 _ = tok_it.next();
4323 break :blk true;4365 break :blk true;
4324 } else false;4366 } else false;
43254367
4326 (if (macro_fn)4368 (if (macro_fn)
4327 transMacroFnDefine(c, &tok_it, checked_name, begin_loc)4369 transMacroFnDefine(c, &tok_it, mangled_name, begin_loc)
4328 else4370 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) {
4330 error.ParseError => continue,4372 error.ParseError => continue,
4331 error.OutOfMemory => |e| return e,4373 error.OutOfMemory => |e| return e,
4332 };4374 };
test/translate_c.zig+14
...@@ -2288,4 +2288,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2288,4 +2288,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2288 \\}2288 \\}
2289 \\pub export var bar: c_int = 4;2289 \\pub export var bar: c_int = 4;
2290 });2290 });
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 });
2291}2305}