| ... | ... | @@ -19,8 +19,6 @@ pub const Error = error{OutOfMemory}; |
| 19 | 19 | const TypeError = Error || error{UnsupportedType}; |
| 20 | 20 | const TransError = TypeError || error{UnsupportedTranslation}; |
| 21 | 21 | |
| 22 | | const DeclTable = std.AutoArrayHashMap(usize, []const u8); |
| 23 | | |
| 24 | 22 | const SymbolTable = std.StringArrayHashMap(*ast.Node); |
| 25 | 23 | const AliasList = std.ArrayList(struct { |
| 26 | 24 | alias: []const u8, |
| ... | ... | @@ -254,24 +252,25 @@ const Scope = struct { |
| 254 | 252 | pub const Context = struct { |
| 255 | 253 | gpa: *mem.Allocator, |
| 256 | 254 | arena: *mem.Allocator, |
| 257 | | token_ids: std.ArrayListUnmanaged(Token.Id), |
| 258 | | token_locs: std.ArrayListUnmanaged(Token.Loc), |
| 259 | | errors: std.ArrayListUnmanaged(ast.Error), |
| 255 | token_ids: std.ArrayListUnmanaged(Token.Id) = .{}, |
| 256 | token_locs: std.ArrayListUnmanaged(Token.Loc) = .{}, |
| 257 | errors: std.ArrayListUnmanaged(ast.Error) = .{}, |
| 260 | 258 | source_buffer: *std.ArrayList(u8), |
| 261 | 259 | err: Error, |
| 262 | 260 | source_manager: *clang.SourceManager, |
| 263 | | decl_table: DeclTable, |
| 261 | decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{}, |
| 264 | 262 | alias_list: AliasList, |
| 265 | 263 | global_scope: *Scope.Root, |
| 266 | 264 | clang_context: *clang.ASTContext, |
| 267 | 265 | mangle_count: u32 = 0, |
| 268 | | root_decls: std.ArrayListUnmanaged(*ast.Node), |
| 266 | root_decls: std.ArrayListUnmanaged(*ast.Node) = .{}, |
| 267 | opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{}, |
| 269 | 268 | |
| 270 | 269 | /// This one is different than the root scope's name table. This contains |
| 271 | 270 | /// a list of names that we found by visiting all the top level decls without |
| 272 | 271 | /// translating them. The other maps are updated as we translate; this one is updated |
| 273 | 272 | /// up front in a pre-processing step. |
| 274 | | global_names: std.StringArrayHashMap(void), |
| 273 | global_names: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 275 | 274 | |
| 276 | 275 | fn getMangle(c: *Context) u32 { |
| 277 | 276 | c.mangle_count += 1; |
| ... | ... | @@ -362,24 +361,21 @@ pub fn translate( |
| 362 | 361 | .source_buffer = &source_buffer, |
| 363 | 362 | .source_manager = ast_unit.getSourceManager(), |
| 364 | 363 | .err = undefined, |
| 365 | | .decl_table = DeclTable.init(gpa), |
| 366 | 364 | .alias_list = AliasList.init(gpa), |
| 367 | 365 | .global_scope = try arena.allocator.create(Scope.Root), |
| 368 | 366 | .clang_context = ast_unit.getASTContext(), |
| 369 | | .global_names = std.StringArrayHashMap(void).init(gpa), |
| 370 | | .token_ids = .{}, |
| 371 | | .token_locs = .{}, |
| 372 | | .errors = .{}, |
| 373 | | .root_decls = .{}, |
| 374 | 367 | }; |
| 375 | 368 | context.global_scope.* = Scope.Root.init(&context); |
| 376 | | defer context.decl_table.deinit(); |
| 377 | | defer context.alias_list.deinit(); |
| 378 | | defer context.token_ids.deinit(gpa); |
| 379 | | defer context.token_locs.deinit(gpa); |
| 380 | | defer context.errors.deinit(gpa); |
| 381 | | defer context.global_names.deinit(); |
| 382 | | defer context.root_decls.deinit(gpa); |
| 369 | defer { |
| 370 | context.decl_table.deinit(gpa); |
| 371 | context.alias_list.deinit(); |
| 372 | context.token_ids.deinit(gpa); |
| 373 | context.token_locs.deinit(gpa); |
| 374 | context.errors.deinit(gpa); |
| 375 | context.global_names.deinit(gpa); |
| 376 | context.root_decls.deinit(gpa); |
| 377 | context.opaque_demotes.deinit(gpa); |
| 378 | } |
| 383 | 379 | |
| 384 | 380 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 385 | 381 | |
| ... | ... | @@ -437,7 +433,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { |
| 437 | 433 | const macro = @ptrCast(*clang.MacroDefinitionRecord, entity); |
| 438 | 434 | const raw_name = macro.getName_getNameStart(); |
| 439 | 435 | const name = try c.str(raw_name); |
| 440 | | _ = try c.global_names.put(name, {}); |
| 436 | _ = try c.global_names.put(c.gpa, name, {}); |
| 441 | 437 | }, |
| 442 | 438 | else => {}, |
| 443 | 439 | } |
| ... | ... | @@ -465,7 +461,7 @@ fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { |
| 465 | 461 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 466 | 462 | if (decl.castToNamedDecl()) |named_decl| { |
| 467 | 463 | const decl_name = try c.str(named_decl.getName_bytes_begin()); |
| 468 | | _ = try c.global_names.put(decl_name, {}); |
| 464 | _ = try c.global_names.put(c.gpa, decl_name, {}); |
| 469 | 465 | } |
| 470 | 466 | } |
| 471 | 467 | |
| ... | ... | @@ -804,7 +800,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 804 | 800 | } |
| 805 | 801 | |
| 806 | 802 | fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !*ast.Node { |
| 807 | | _ = try c.decl_table.put(@ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name); |
| 803 | _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name); |
| 808 | 804 | return transCreateNodeIdentifier(c, builtin_name); |
| 809 | 805 | } |
| 810 | 806 | |
| ... | ... | @@ -851,7 +847,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_lev |
| 851 | 847 | return transCreateNodeIdentifier(c, checked_name); |
| 852 | 848 | } |
| 853 | 849 | |
| 854 | | _ = try c.decl_table.put(@ptrToInt(typedef_decl.getCanonicalDecl()), checked_name); |
| 850 | _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name); |
| 855 | 851 | const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null; |
| 856 | 852 | try addTopLevelDecl(c, checked_name, node); |
| 857 | 853 | return transCreateNodeIdentifier(c, checked_name); |
| ... | ... | @@ -918,7 +914,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 918 | 914 | } |
| 919 | 915 | |
| 920 | 916 | const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name }); |
| 921 | | _ = try c.decl_table.put(@ptrToInt(record_decl.getCanonicalDecl()), name); |
| 917 | _ = try c.decl_table.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name); |
| 922 | 918 | |
| 923 | 919 | const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null; |
| 924 | 920 | const mut_tok = try appendToken(c, .Keyword_const, "const"); |
| ... | ... | @@ -930,6 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 930 | 926 | const init_node = blk: { |
| 931 | 927 | const rp = makeRestorePoint(c); |
| 932 | 928 | const record_def = record_decl.getDefinition() orelse { |
| 929 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); |
| 933 | 930 | const opaque_type = try transCreateNodeOpaqueType(c); |
| 934 | 931 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 935 | 932 | break :blk opaque_type; |
| ... | ... | @@ -954,6 +951,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 954 | 951 | const field_qt = field_decl.getType(); |
| 955 | 952 | |
| 956 | 953 | if (field_decl.isBitField()) { |
| 954 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); |
| 957 | 955 | const opaque_type = try transCreateNodeOpaqueType(c); |
| 958 | 956 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 959 | 957 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); |
| ... | ... | @@ -961,6 +959,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 961 | 959 | } |
| 962 | 960 | |
| 963 | 961 | if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) { |
| 962 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); |
| 964 | 963 | const opaque_type = try transCreateNodeOpaqueType(c); |
| 965 | 964 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 966 | 965 | try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name}); |
| ... | ... | @@ -979,6 +978,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 979 | 978 | _ = try appendToken(c, .Colon, ":"); |
| 980 | 979 | const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) { |
| 981 | 980 | error.UnsupportedType => { |
| 981 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); |
| 982 | 982 | const opaque_type = try transCreateNodeOpaqueType(c); |
| 983 | 983 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 984 | 984 | try emitWarning(c, record_loc, "{} demoted to opaque type - unable to translate type of field {}", .{ container_kind_name, raw_name }); |
| ... | ... | @@ -988,13 +988,13 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 988 | 988 | }; |
| 989 | 989 | |
| 990 | 990 | const align_expr = blk_2: { |
| 991 | | const alignment = field_decl.getAlignedAttribute(rp.c.clang_context); |
| 991 | const alignment = field_decl.getAlignedAttribute(c.clang_context); |
| 992 | 992 | if (alignment != 0) { |
| 993 | | _ = try appendToken(rp.c, .Keyword_align, "align"); |
| 994 | | _ = try appendToken(rp.c, .LParen, "("); |
| 993 | _ = try appendToken(c, .Keyword_align, "align"); |
| 994 | _ = try appendToken(c, .LParen, "("); |
| 995 | 995 | // Clang reports the alignment in bits |
| 996 | | const expr = try transCreateNodeInt(rp.c, alignment / 8); |
| 997 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 996 | const expr = try transCreateNodeInt(c, alignment / 8); |
| 997 | _ = try appendToken(c, .RParen, ")"); |
| 998 | 998 | |
| 999 | 999 | break :blk_2 expr; |
| 1000 | 1000 | } |
| ... | ... | @@ -1013,6 +1013,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as |
| 1013 | 1013 | |
| 1014 | 1014 | if (is_anon) { |
| 1015 | 1015 | _ = try c.decl_table.put( |
| 1016 | c.gpa, |
| 1016 | 1017 | @ptrToInt(field_decl.getCanonicalDecl()), |
| 1017 | 1018 | raw_name, |
| 1018 | 1019 | ); |
| ... | ... | @@ -1065,7 +1066,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node |
| 1065 | 1066 | } |
| 1066 | 1067 | |
| 1067 | 1068 | const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name}); |
| 1068 | | _ = try c.decl_table.put(@ptrToInt(enum_decl.getCanonicalDecl()), name); |
| 1069 | _ = try c.decl_table.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name); |
| 1069 | 1070 | |
| 1070 | 1071 | const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null; |
| 1071 | 1072 | const mut_tok = try appendToken(c, .Keyword_const, "const"); |
| ... | ... | @@ -1204,8 +1205,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node |
| 1204 | 1205 | }; |
| 1205 | 1206 | mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items); |
| 1206 | 1207 | break :blk &container_node.base; |
| 1207 | | } else |
| 1208 | | try transCreateNodeOpaqueType(c); |
| 1208 | } else blk: { |
| 1209 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {}); |
| 1210 | break :blk try transCreateNodeOpaqueType(c); |
| 1211 | }; |
| 1209 | 1212 | |
| 1210 | 1213 | const semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 1211 | 1214 | const node = try ast.Node.VarDecl.create(c.arena, .{ |
| ... | ... | @@ -4767,7 +4770,7 @@ fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLo |
| 4767 | 4770 | optional_node.rhs = try transQualType(rp, child_qt, source_loc); |
| 4768 | 4771 | return &optional_node.base; |
| 4769 | 4772 | } |
| 4770 | | if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc)) { |
| 4773 | if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) { |
| 4771 | 4774 | const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?"); |
| 4772 | 4775 | const pointer_node = try transCreateNodePtrType( |
| 4773 | 4776 | rp.c, |
| ... | ... | @@ -4853,6 +4856,50 @@ fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLo |
| 4853 | 4856 | } |
| 4854 | 4857 | } |
| 4855 | 4858 | |
| 4859 | fn qualTypeWasDemotedToOpaque(c: *Context, qt: clang.QualType) bool { |
| 4860 | const ty = qt.getTypePtr(); |
| 4861 | switch (qt.getTypeClass()) { |
| 4862 | .Typedef => { |
| 4863 | const typedef_ty = @ptrCast(*const clang.TypedefType, ty); |
| 4864 | |
| 4865 | const typedef_decl = typedef_ty.getDecl(); |
| 4866 | const underlying_type = typedef_decl.getUnderlyingType(); |
| 4867 | return qualTypeWasDemotedToOpaque(c, underlying_type); |
| 4868 | }, |
| 4869 | .Record => { |
| 4870 | const record_ty = @ptrCast(*const clang.RecordType, ty); |
| 4871 | |
| 4872 | const record_decl = record_ty.getDecl(); |
| 4873 | const canonical = @ptrToInt(record_decl.getCanonicalDecl()); |
| 4874 | return c.opaque_demotes.contains(canonical); |
| 4875 | }, |
| 4876 | .Enum => { |
| 4877 | const enum_ty = @ptrCast(*const clang.EnumType, ty); |
| 4878 | |
| 4879 | const enum_decl = enum_ty.getDecl(); |
| 4880 | const canonical = @ptrToInt(enum_decl.getCanonicalDecl()); |
| 4881 | return c.opaque_demotes.contains(canonical); |
| 4882 | }, |
| 4883 | .Elaborated => { |
| 4884 | const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty); |
| 4885 | return qualTypeWasDemotedToOpaque(c, elaborated_ty.getNamedType()); |
| 4886 | }, |
| 4887 | .Decayed => { |
| 4888 | const decayed_ty = @ptrCast(*const clang.DecayedType, ty); |
| 4889 | return qualTypeWasDemotedToOpaque(c, decayed_ty.getDecayedType()); |
| 4890 | }, |
| 4891 | .Attributed => { |
| 4892 | const attributed_ty = @ptrCast(*const clang.AttributedType, ty); |
| 4893 | return qualTypeWasDemotedToOpaque(c, attributed_ty.getEquivalentType()); |
| 4894 | }, |
| 4895 | .MacroQualified => { |
| 4896 | const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty); |
| 4897 | return qualTypeWasDemotedToOpaque(c, macroqualified_ty.getModifiedType()); |
| 4898 | }, |
| 4899 | else => return false, |
| 4900 | } |
| 4901 | } |
| 4902 | |
| 4856 | 4903 | fn isCVoid(qt: clang.QualType) bool { |
| 4857 | 4904 | const ty = qt.getTypePtr(); |
| 4858 | 4905 | if (ty.getTypeClass() == .Builtin) { |