| ... | ... | @@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void { |
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | fn fail( |
| 82 | c: *Context, |
| 83 | err: anytype, |
| 84 | source_loc: TokenIndex, |
| 85 | comptime format: []const u8, |
| 86 | args: anytype, |
| 87 | ) (@TypeOf(err) || error{OutOfMemory}) { |
| 88 | try warn(c, &c.global_scope.base, source_loc, format, args); |
| 89 | return err; |
| 90 | } |
| 91 | |
| 81 | 92 | fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void { |
| 82 | 93 | // location |
| 83 | 94 | // pub const name = @compileError(msg); |
| ... | ... | @@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void { |
| 185 | 196 | for (c.tree.root_decls) |node| { |
| 186 | 197 | const data = node_data[@intFromEnum(node)]; |
| 187 | 198 | switch (node_tags[@intFromEnum(node)]) { |
| 188 | | .typedef => @panic("TODO"), |
| 199 | .typedef => {}, |
| 189 | 200 | |
| 190 | 201 | .struct_decl_two, |
| 191 | 202 | .union_decl_two, |
| ... | ... | @@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void { |
| 243 | 254 | fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 244 | 255 | const node_tags = c.tree.nodes.items(.tag); |
| 245 | 256 | const node_data = c.tree.nodes.items(.data); |
| 257 | const node_ty = c.tree.nodes.items(.ty); |
| 246 | 258 | const data = node_data[@intFromEnum(decl)]; |
| 247 | 259 | switch (node_tags[@intFromEnum(decl)]) { |
| 248 | 260 | .typedef => { |
| ... | ... | @@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 252 | 264 | .struct_decl_two, |
| 253 | 265 | .union_decl_two, |
| 254 | 266 | => { |
| 255 | | var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs }; |
| 256 | | var field_count: u2 = 0; |
| 257 | | if (fields[0] != .none) field_count += 1; |
| 258 | | if (fields[1] != .none) field_count += 1; |
| 259 | | try transRecordDecl(c, scope, decl, fields[0..field_count]); |
| 267 | try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); |
| 260 | 268 | }, |
| 261 | 269 | .struct_decl, |
| 262 | 270 | .union_decl, |
| 263 | 271 | => { |
| 264 | | const fields = c.tree.data[data.range.start..data.range.end]; |
| 265 | | try transRecordDecl(c, scope, decl, fields); |
| 272 | try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); |
| 266 | 273 | }, |
| 267 | 274 | |
| 268 | 275 | .enum_decl_two => { |
| ... | ... | @@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 270 | 277 | var field_count: u8 = 0; |
| 271 | 278 | if (fields[0] != .none) field_count += 1; |
| 272 | 279 | if (fields[1] != .none) field_count += 1; |
| 273 | | try transEnumDecl(c, scope, decl, fields[0..field_count]); |
| 280 | const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; |
| 281 | try transEnumDecl(c, scope, enum_decl, fields[0..field_count]); |
| 274 | 282 | }, |
| 275 | 283 | .enum_decl => { |
| 276 | 284 | const fields = c.tree.data[data.range.start..data.range.end]; |
| 277 | | try transEnumDecl(c, scope, decl, fields); |
| 285 | const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; |
| 286 | try transEnumDecl(c, scope, enum_decl, fields); |
| 278 | 287 | }, |
| 279 | 288 | |
| 280 | 289 | .enum_field_decl, |
| ... | ... | @@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 294 | 303 | .inline_fn_def, |
| 295 | 304 | .inline_static_fn_def, |
| 296 | 305 | => { |
| 297 | | try transFnDecl(c, decl); |
| 306 | try transFnDecl(c, decl, true); |
| 298 | 307 | }, |
| 299 | 308 | |
| 300 | 309 | .@"var", |
| ... | ... | @@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 304 | 313 | .threadlocal_extern_var, |
| 305 | 314 | .threadlocal_static_var, |
| 306 | 315 | => { |
| 307 | | try transVarDecl(c, decl, null); |
| 316 | try transVarDecl(c, decl); |
| 308 | 317 | }, |
| 309 | 318 | .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}), |
| 310 | 319 | else => unreachable, |
| 311 | 320 | } |
| 312 | 321 | } |
| 313 | 322 | |
| 314 | | fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void { |
| 315 | | @panic("TODO"); |
| 323 | fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void { |
| 324 | const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)]; |
| 325 | const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)]; |
| 326 | |
| 327 | const toplevel = scope.id == .root; |
| 328 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| 329 | |
| 330 | var name: []const u8 = c.tree.tokSlice(data.decl.name); |
| 331 | try c.typedefs.put(c.gpa, name, {}); |
| 332 | |
| 333 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| 334 | |
| 335 | const typedef_loc = data.decl.name; |
| 336 | const init_node = transType(c, scope, ty, .standard, typedef_loc) catch |err| switch (err) { |
| 337 | error.UnsupportedType => { |
| 338 | return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{}); |
| 339 | }, |
| 340 | error.OutOfMemory => |e| return e, |
| 341 | }; |
| 342 | |
| 343 | const payload = try c.arena.create(ast.Payload.SimpleVarDecl); |
| 344 | payload.* = .{ |
| 345 | .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(toplevel)] }, |
| 346 | .data = .{ |
| 347 | .name = name, |
| 348 | .init = init_node, |
| 349 | }, |
| 350 | }; |
| 351 | const node = ZigNode.initPayload(&payload.base); |
| 352 | |
| 353 | if (toplevel) { |
| 354 | try addTopLevelDecl(c, name, node); |
| 355 | } else { |
| 356 | try scope.appendNode(node); |
| 357 | if (node.tag() != .pub_var_simple) { |
| 358 | try bs.discardVariable(c, name); |
| 359 | } |
| 360 | } |
| 316 | 361 | } |
| 317 | 362 | |
| 318 | 363 | fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { |
| ... | ... | @@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { |
| 330 | 375 | return cur_name; |
| 331 | 376 | } |
| 332 | 377 | |
| 333 | | fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void { |
| 334 | | const node_types = c.tree.nodes.items(.ty); |
| 335 | | const raw_record_ty = node_types[@intFromEnum(record_node)]; |
| 336 | | const record_decl = raw_record_ty.getRecord().?; |
| 378 | fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void { |
| 379 | const record_decl = record_ty.getRecord().?; |
| 337 | 380 | if (c.decl_table.get(@intFromPtr(record_decl))) |_| |
| 338 | 381 | return; // Avoid processing this decl twice |
| 339 | 382 | const toplevel = scope.id == .root; |
| 340 | 383 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| 341 | 384 | |
| 342 | | const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct"; |
| 385 | const container_kind: ZigTag = if (record_ty.is(.@"union")) .@"union" else .@"struct"; |
| 343 | 386 | const container_kind_name: []const u8 = @tagName(container_kind); |
| 344 | 387 | |
| 345 | 388 | var is_unnamed = false; |
| ... | ... | @@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 350 | 393 | bare_name = typedef_name; |
| 351 | 394 | name = typedef_name; |
| 352 | 395 | } else { |
| 353 | | if (raw_record_ty.isAnonymousRecord(c.comp)) { |
| 396 | if (record_ty.isAnonymousRecord(c.comp)) { |
| 354 | 397 | bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()}); |
| 355 | 398 | is_unnamed = true; |
| 356 | 399 | } |
| ... | ... | @@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 364 | 407 | |
| 365 | 408 | const is_pub = toplevel and !is_unnamed; |
| 366 | 409 | const init_node = blk: { |
| 410 | if (record_decl.isIncomplete()) { |
| 411 | try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {}); |
| 412 | break :blk ZigTag.opaque_literal.init(); |
| 413 | } |
| 414 | |
| 367 | 415 | var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len); |
| 368 | 416 | defer fields.deinit(); |
| 369 | 417 | |
| ... | ... | @@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 377 | 425 | // layout, then we can just use a simple `extern` type. If it does have attributes, |
| 378 | 426 | // then we need to inspect the layout and assign an `align` value for each field. |
| 379 | 427 | const has_alignment_attributes = record_decl.field_attributes != null or |
| 380 | | raw_record_ty.hasAttribute(.@"packed") or |
| 381 | | raw_record_ty.hasAttribute(.aligned); |
| 428 | record_ty.hasAttribute(.@"packed") or |
| 429 | record_ty.hasAttribute(.aligned); |
| 382 | 430 | const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null; |
| 383 | 431 | |
| 384 | | // Iterate over field nodes so that we translate any type decls included in this record decl. |
| 385 | | // TODO: Move this logic into `fn transType()` instead of handling decl translation here. |
| 386 | | for (field_nodes) |field_node| { |
| 387 | | const field_raw_ty = node_types[@intFromEnum(field_node)]; |
| 388 | | if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node); |
| 389 | | } |
| 390 | | |
| 391 | 432 | for (record_decl.fields, 0..) |field, field_index| { |
| 392 | 433 | const field_loc = field.name_tok; |
| 393 | 434 | |
| ... | ... | @@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 473 | 514 | } |
| 474 | 515 | } |
| 475 | 516 | |
| 476 | | fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { |
| 517 | fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void { |
| 477 | 518 | const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)]; |
| 478 | 519 | const fn_ty = raw_ty.canonicalize(.standard); |
| 479 | 520 | const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)]; |
| ... | ... | @@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { |
| 498 | 539 | |
| 499 | 540 | else => unreachable, |
| 500 | 541 | }, |
| 542 | .is_pub = is_pub, |
| 501 | 543 | }; |
| 502 | 544 | |
| 503 | 545 | const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) { |
| ... | ... | @@ -566,22 +608,22 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { |
| 566 | 608 | return addTopLevelDecl(c, fn_name, proto_node); |
| 567 | 609 | } |
| 568 | 610 | |
| 569 | | fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void { |
| 570 | | @panic("TODO"); |
| 611 | fn transVarDecl(c: *Context, node: NodeIndex) Error!void { |
| 612 | const data = c.tree.nodes.items(.data)[@intFromEnum(node)]; |
| 613 | const name = c.tree.tokSlice(data.decl.name); |
| 614 | return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{}); |
| 571 | 615 | } |
| 572 | 616 | |
| 573 | | fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void { |
| 574 | | const node_types = c.tree.nodes.items(.ty); |
| 575 | | const ty = node_types[@intFromEnum(enum_decl)]; |
| 576 | | if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_| |
| 617 | fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void { |
| 618 | if (c.decl_table.get(@intFromPtr(enum_decl))) |_| |
| 577 | 619 | return; // Avoid processing this decl twice |
| 578 | 620 | const toplevel = scope.id == .root; |
| 579 | 621 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| 580 | 622 | |
| 581 | 623 | var is_unnamed = false; |
| 582 | | var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name); |
| 624 | var bare_name: []const u8 = c.mapper.lookup(enum_decl.name); |
| 583 | 625 | var name = bare_name; |
| 584 | | if (c.unnamed_typedefs.get(@intFromPtr(ty.data.@"enum"))) |typedef_name| { |
| 626 | if (c.unnamed_typedefs.get(@intFromPtr(enum_decl))) |typedef_name| { |
| 585 | 627 | bare_name = typedef_name; |
| 586 | 628 | name = typedef_name; |
| 587 | 629 | } else { |
| ... | ... | @@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 592 | 634 | name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); |
| 593 | 635 | } |
| 594 | 636 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| 595 | | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(ty.data.@"enum"), name); |
| 637 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl), name); |
| 596 | 638 | |
| 597 | | const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: { |
| 598 | | for (ty.data.@"enum".fields, field_nodes) |field, field_node| { |
| 639 | const enum_type_node = if (!enum_decl.isIncomplete()) blk: { |
| 640 | for (enum_decl.fields, field_nodes) |field, field_node| { |
| 599 | 641 | var enum_val_name: []const u8 = c.mapper.lookup(field.name); |
| 600 | 642 | if (!toplevel) { |
| 601 | 643 | enum_val_name = try bs.makeMangledName(c, enum_val_name); |
| ... | ... | @@ -621,14 +663,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 621 | 663 | } |
| 622 | 664 | } |
| 623 | 665 | |
| 624 | | break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) { |
| 666 | break :blk transType(c, scope, enum_decl.tag_ty, .standard, 0) catch |err| switch (err) { |
| 625 | 667 | error.UnsupportedType => { |
| 626 | 668 | return failDecl(c, 0, name, "unable to translate enum integer type", .{}); |
| 627 | 669 | }, |
| 628 | 670 | else => |e| return e, |
| 629 | 671 | }; |
| 630 | 672 | } else blk: { |
| 631 | | try c.opaque_demotes.put(c.gpa, @intFromPtr(ty.data.@"enum"), {}); |
| 673 | try c.opaque_demotes.put(c.gpa, @intFromPtr(enum_decl), {}); |
| 632 | 674 | break :blk ZigTag.opaque_literal.init(); |
| 633 | 675 | }; |
| 634 | 676 | |
| ... | ... | @@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 654 | 696 | } |
| 655 | 697 | } |
| 656 | 698 | |
| 699 | fn getTypeStr(c: *Context, ty: Type) ![]const u8 { |
| 700 | var buf: std.ArrayListUnmanaged(u8) = .{}; |
| 701 | defer buf.deinit(c.gpa); |
| 702 | const w = buf.writer(c.gpa); |
| 703 | try ty.print(c.mapper, c.comp.langopts, w); |
| 704 | return c.arena.dupe(u8, buf.items); |
| 705 | } |
| 706 | |
| 657 | 707 | fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode { |
| 658 | 708 | const ty = raw_ty.canonicalize(qual_handling); |
| 709 | if (ty.qual.atomic) { |
| 710 | const type_name = try getTypeStr(c, ty); |
| 711 | return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); |
| 712 | } |
| 713 | |
| 659 | 714 | switch (ty.specifier) { |
| 660 | 715 | .void => return ZigTag.type.create(c.arena, "anyopaque"), |
| 661 | 716 | .bool => return ZigTag.type.create(c.arena, "bool"), |
| ... | ... | @@ -678,13 +733,53 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH |
| 678 | 733 | .long_double => return ZigTag.type.create(c.arena, "c_longdouble"), |
| 679 | 734 | .float80 => return ZigTag.type.create(c.arena, "f80"), |
| 680 | 735 | .float128 => return ZigTag.type.create(c.arena, "f128"), |
| 681 | | .@"enum" => @panic("TODO"), |
| 682 | | .pointer, |
| 683 | | .unspecified_variable_len_array, |
| 736 | .@"enum" => { |
| 737 | const enum_decl = ty.data.@"enum"; |
| 738 | var trans_scope = scope; |
| 739 | if (enum_decl.name != .empty) { |
| 740 | const decl_name = c.mapper.lookup(enum_decl.name); |
| 741 | if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base; |
| 742 | } |
| 743 | try transEnumDecl(c, trans_scope, enum_decl, &.{}); |
| 744 | return ZigTag.identifier.create(c.arena, c.decl_table.get(@intFromPtr(enum_decl)).?); |
| 745 | }, |
| 746 | .pointer => { |
| 747 | const child_type = ty.elemType(); |
| 748 | |
| 749 | const is_fn_proto = child_type.isFunc(); |
| 750 | const is_const = is_fn_proto or child_type.isConst(); |
| 751 | const is_volatile = child_type.qual.@"volatile"; |
| 752 | const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); |
| 753 | const ptr_info = .{ |
| 754 | .is_const = is_const, |
| 755 | .is_volatile = is_volatile, |
| 756 | .elem_type = elem_type, |
| 757 | }; |
| 758 | if (is_fn_proto or |
| 759 | typeIsOpaque(c, child_type) or |
| 760 | typeWasDemotedToOpaque(c, child_type)) |
| 761 | { |
| 762 | const ptr = try ZigTag.single_pointer.create(c.arena, ptr_info); |
| 763 | return ZigTag.optional_type.create(c.arena, ptr); |
| 764 | } |
| 765 | |
| 766 | return ZigTag.c_pointer.create(c.arena, ptr_info); |
| 767 | }, |
| 768 | .unspecified_variable_len_array, .incomplete_array => { |
| 769 | const child_type = ty.elemType(); |
| 770 | const is_const = child_type.qual.@"const"; |
| 771 | const is_volatile = child_type.qual.@"volatile"; |
| 772 | const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); |
| 773 | |
| 774 | return ZigTag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); |
| 775 | }, |
| 684 | 776 | .array, |
| 685 | 777 | .static_array, |
| 686 | | .incomplete_array, |
| 687 | | => @panic("TODO"), |
| 778 | => { |
| 779 | const size = ty.arrayLen().?; |
| 780 | const elem_type = try transType(c, scope, ty.elemType(), qual_handling, source_loc); |
| 781 | return ZigTag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); |
| 782 | }, |
| 688 | 783 | .func, |
| 689 | 784 | .var_args_func, |
| 690 | 785 | .old_style_func, |
| ... | ... | @@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH |
| 698 | 793 | const name_id = c.mapper.lookup(record_decl.name); |
| 699 | 794 | if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base; |
| 700 | 795 | } |
| 796 | try transRecordDecl(c, trans_scope, ty); |
| 701 | 797 | const name = c.decl_table.get(@intFromPtr(ty.data.record)).?; |
| 702 | 798 | return ZigTag.identifier.create(c.arena, name); |
| 703 | 799 | }, |
| ... | ... | @@ -927,7 +1023,9 @@ fn transFnType( |
| 927 | 1023 | } |
| 928 | 1024 | |
| 929 | 1025 | fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode { |
| 930 | | return transExpr(c, node, .unused); |
| 1026 | _ = c; |
| 1027 | _ = node; |
| 1028 | return error.UnsupportedTranslation; |
| 931 | 1029 | } |
| 932 | 1030 | |
| 933 | 1031 | fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void { |
| ... | ... | @@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block |
| 952 | 1050 | } |
| 953 | 1051 | } |
| 954 | 1052 | |
| 1053 | fn recordHasBitfield(record: *const Type.Record) bool { |
| 1054 | if (record.isIncomplete()) return false; |
| 1055 | for (record.fields) |field| { |
| 1056 | if (!field.isRegularField()) return true; |
| 1057 | } |
| 1058 | return false; |
| 1059 | } |
| 1060 | |
| 1061 | fn typeIsOpaque(c: *Context, ty: Type) bool { |
| 1062 | return switch (ty.specifier) { |
| 1063 | .void => true, |
| 1064 | .@"struct", .@"union" => recordHasBitfield(ty.getRecord().?), |
| 1065 | .typeof_type => typeIsOpaque(c, ty.data.sub_type.*), |
| 1066 | .typeof_expr => typeIsOpaque(c, ty.data.expr.ty), |
| 1067 | .attributed => typeIsOpaque(c, ty.data.attributed.base), |
| 1068 | else => false, |
| 1069 | }; |
| 1070 | } |
| 1071 | |
| 1072 | fn typeWasDemotedToOpaque(c: *Context, ty: Type) bool { |
| 1073 | switch (ty.specifier) { |
| 1074 | .@"struct", .@"union" => { |
| 1075 | const record = ty.getRecord().?; |
| 1076 | if (c.opaque_demotes.contains(@intFromPtr(record))) return true; |
| 1077 | for (record.fields) |field| { |
| 1078 | if (typeWasDemotedToOpaque(c, field.ty)) return true; |
| 1079 | } |
| 1080 | return false; |
| 1081 | }, |
| 1082 | |
| 1083 | .@"enum" => return c.opaque_demotes.contains(@intFromPtr(ty.data.@"enum")), |
| 1084 | |
| 1085 | .typeof_type => return typeWasDemotedToOpaque(c, ty.data.sub_type.*), |
| 1086 | .typeof_expr => return typeWasDemotedToOpaque(c, ty.data.expr.ty), |
| 1087 | .attributed => return typeWasDemotedToOpaque(c, ty.data.attributed.base), |
| 1088 | else => return false, |
| 1089 | } |
| 1090 | } |
| 1091 | |
| 955 | 1092 | fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode { |
| 956 | 1093 | var block_scope = try Scope.Block.init(c, scope, false); |
| 957 | 1094 | defer block_scope.deinit(); |