| ... | ... | @@ -83,6 +83,7 @@ const Scope = struct { |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | 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 | 87 | fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 { |
| 87 | 88 | var proposed_name = name; |
| 88 | 89 | while (scope.contains(proposed_name)) { |
| ... | ... | @@ -136,15 +137,37 @@ const Scope = struct { |
| 136 | 137 | }; |
| 137 | 138 | } |
| 138 | 139 | |
| 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 |
| 141 | 165 | scope.macro_table.contains(name); |
| 142 | 166 | } |
| 143 | 167 | |
| 168 | /// Check if the global scope contains the name, includes all decls that haven't been translated yet. |
| 144 | 169 | 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); |
| 148 | 171 | } |
| 149 | 172 | }; |
| 150 | 173 | |
| ... | ... | @@ -308,9 +331,7 @@ pub fn translate( |
| 308 | 331 | }; |
| 309 | 332 | context.global_scope.* = Scope.Root.init(&context); |
| 310 | 333 | |
| 311 | | if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorNamesOnlyC)) { |
| 312 | | return context.err; |
| 313 | | } |
| 334 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 314 | 335 | |
| 315 | 336 | if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { |
| 316 | 337 | return context.err; |
| ... | ... | @@ -339,6 +360,29 @@ pub fn translate( |
| 339 | 360 | return tree; |
| 340 | 361 | } |
| 341 | 362 | |
| 363 | fn 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 | |
| 342 | 386 | extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool { |
| 343 | 387 | const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); |
| 344 | 388 | declVisitorNamesOnly(c, decl) catch |err| { |
| ... | ... | @@ -4272,7 +4316,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4272 | 4316 | var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); |
| 4273 | 4317 | const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); |
| 4274 | 4318 | var tok_list = ctok.TokenList.init(c.a()); |
| 4275 | | const scope = &c.global_scope.base; |
| 4319 | const scope = c.global_scope; |
| 4276 | 4320 | |
| 4277 | 4321 | while (it.I != it_end.I) : (it.I += 1) { |
| 4278 | 4322 | const entity = ZigClangPreprocessingRecord_iterator_deref(it); |
| ... | ... | @@ -4285,14 +4329,8 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4285 | 4329 | |
| 4286 | 4330 | const name = try c.str(raw_name); |
| 4287 | 4331 | |
| 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 | 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 | 4334 | error.OutOfMemory => |e| return e, |
| 4297 | 4335 | else => { |
| 4298 | 4336 | continue; |
| ... | ... | @@ -4307,7 +4345,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4307 | 4345 | .Identifier => { |
| 4308 | 4346 | // if it equals itself, ignore. for example, from stdio.h: |
| 4309 | 4347 | // #define stdin stdin |
| 4310 | | if (mem.eql(u8, checked_name, next.bytes)) { |
| 4348 | if (mem.eql(u8, name, next.bytes)) { |
| 4311 | 4349 | continue; |
| 4312 | 4350 | } |
| 4313 | 4351 | }, |
| ... | ... | @@ -4318,15 +4356,19 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4318 | 4356 | }, |
| 4319 | 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 | 4363 | const macro_fn = if (tok_it.peek().?.id == .Fn) blk: { |
| 4322 | 4364 | _ = tok_it.next(); |
| 4323 | 4365 | break :blk true; |
| 4324 | 4366 | } else false; |
| 4325 | 4367 | |
| 4326 | 4368 | (if (macro_fn) |
| 4327 | | transMacroFnDefine(c, &tok_it, checked_name, begin_loc) |
| 4369 | transMacroFnDefine(c, &tok_it, mangled_name, begin_loc) |
| 4328 | 4370 | 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 | 4372 | error.ParseError => continue, |
| 4331 | 4373 | error.OutOfMemory => |e| return e, |
| 4332 | 4374 | }; |