|
|
|
@@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn fail(
|
|
|
|
|
c: *Context,
|
|
|
|
|
err: anytype,
|
|
|
|
|
source_loc: TokenIndex,
|
|
|
|
|
comptime format: []const u8,
|
|
|
|
|
args: anytype,
|
|
|
|
|
) (@TypeOf(err) || error{OutOfMemory}) {
|
|
|
|
|
try warn(c, &c.global_scope.base, source_loc, format, args);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void {
|
|
|
|
|
// location
|
|
|
|
|
// pub const name = @compileError(msg);
|
|
|
|
@@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void {
|
|
|
|
|
for (c.tree.root_decls) |node| {
|
|
|
|
|
const data = node_data[@intFromEnum(node)];
|
|
|
|
|
switch (node_tags[@intFromEnum(node)]) {
|
|
|
|
|
.typedef => @panic("TODO"),
|
|
|
|
|
.typedef => {},
|
|
|
|
|
|
|
|
|
|
.struct_decl_two,
|
|
|
|
|
.union_decl_two,
|
|
|
|
@@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void {
|
|
|
|
|
fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
|
|
|
|
|
const node_tags = c.tree.nodes.items(.tag);
|
|
|
|
|
const node_data = c.tree.nodes.items(.data);
|
|
|
|
|
const node_ty = c.tree.nodes.items(.ty);
|
|
|
|
|
const data = node_data[@intFromEnum(decl)];
|
|
|
|
|
switch (node_tags[@intFromEnum(decl)]) {
|
|
|
|
|
.typedef => {
|
|
|
|
@@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
|
|
|
|
|
.struct_decl_two,
|
|
|
|
|
.union_decl_two,
|
|
|
|
|
=> {
|
|
|
|
|
var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs };
|
|
|
|
|
var field_count: u2 = 0;
|
|
|
|
|
if (fields[0] != .none) field_count += 1;
|
|
|
|
|
if (fields[1] != .none) field_count += 1;
|
|
|
|
|
try transRecordDecl(c, scope, decl, fields[0..field_count]);
|
|
|
|
|
try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
|
|
|
|
|
},
|
|
|
|
|
.struct_decl,
|
|
|
|
|
.union_decl,
|
|
|
|
|
=> {
|
|
|
|
|
const fields = c.tree.data[data.range.start..data.range.end];
|
|
|
|
|
try transRecordDecl(c, scope, decl, fields);
|
|
|
|
|
try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.enum_decl_two => {
|
|
|
|
@@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
|
|
|
|
|
var field_count: u8 = 0;
|
|
|
|
|
if (fields[0] != .none) field_count += 1;
|
|
|
|
|
if (fields[1] != .none) field_count += 1;
|
|
|
|
|
try transEnumDecl(c, scope, decl, fields[0..field_count]);
|
|
|
|
|
const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum";
|
|
|
|
|
try transEnumDecl(c, scope, enum_decl, fields[0..field_count]);
|
|
|
|
|
},
|
|
|
|
|
.enum_decl => {
|
|
|
|
|
const fields = c.tree.data[data.range.start..data.range.end];
|
|
|
|
|
try transEnumDecl(c, scope, decl, fields);
|
|
|
|
|
const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum";
|
|
|
|
|
try transEnumDecl(c, scope, enum_decl, fields);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.enum_field_decl,
|
|
|
|
@@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
|
|
|
|
|
.inline_fn_def,
|
|
|
|
|
.inline_static_fn_def,
|
|
|
|
|
=> {
|
|
|
|
|
try transFnDecl(c, decl);
|
|
|
|
|
try transFnDecl(c, decl, true);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.@"var",
|
|
|
|
@@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void {
|
|
|
|
|
.threadlocal_extern_var,
|
|
|
|
|
.threadlocal_static_var,
|
|
|
|
|
=> {
|
|
|
|
|
try transVarDecl(c, decl, null);
|
|
|
|
|
try transVarDecl(c, decl);
|
|
|
|
|
},
|
|
|
|
|
.static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}),
|
|
|
|
|
else => unreachable,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
|
|
|
|
|
@panic("TODO");
|
|
|
|
|
fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void {
|
|
|
|
|
const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)];
|
|
|
|
|
const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)];
|
|
|
|
|
|
|
|
|
|
const toplevel = scope.id == .root;
|
|
|
|
|
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
|
|
|
|
|
|
|
|
|
var name: []const u8 = c.tree.tokSlice(data.decl.name);
|
|
|
|
|
try c.typedefs.put(c.gpa, name, {});
|
|
|
|
|
|
|
|
|
|
if (!toplevel) name = try bs.makeMangledName(c, name);
|
|
|
|
|
|
|
|
|
|
const typedef_loc = data.decl.name;
|
|
|
|
|
const init_node = transType(c, scope, ty, .standard, typedef_loc) catch |err| switch (err) {
|
|
|
|
|
error.UnsupportedType => {
|
|
|
|
|
return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{});
|
|
|
|
|
},
|
|
|
|
|
error.OutOfMemory => |e| return e,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
|
|
|
|
|
payload.* = .{
|
|
|
|
|
.base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(toplevel)] },
|
|
|
|
|
.data = .{
|
|
|
|
|
.name = name,
|
|
|
|
|
.init = init_node,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const node = ZigNode.initPayload(&payload.base);
|
|
|
|
|
|
|
|
|
|
if (toplevel) {
|
|
|
|
|
try addTopLevelDecl(c, name, node);
|
|
|
|
|
} else {
|
|
|
|
|
try scope.appendNode(node);
|
|
|
|
|
if (node.tag() != .pub_var_simple) {
|
|
|
|
|
try bs.discardVariable(c, name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
|
|
|
|
@@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 {
|
|
|
|
|
return cur_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void {
|
|
|
|
|
const node_types = c.tree.nodes.items(.ty);
|
|
|
|
|
const raw_record_ty = node_types[@intFromEnum(record_node)];
|
|
|
|
|
const record_decl = raw_record_ty.getRecord().?;
|
|
|
|
|
fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void {
|
|
|
|
|
const record_decl = record_ty.getRecord().?;
|
|
|
|
|
if (c.decl_table.get(@intFromPtr(record_decl))) |_|
|
|
|
|
|
return; // Avoid processing this decl twice
|
|
|
|
|
const toplevel = scope.id == .root;
|
|
|
|
|
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
|
|
|
|
|
|
|
|
|
const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct";
|
|
|
|
|
const container_kind: ZigTag = if (record_ty.is(.@"union")) .@"union" else .@"struct";
|
|
|
|
|
const container_kind_name: []const u8 = @tagName(container_kind);
|
|
|
|
|
|
|
|
|
|
var is_unnamed = false;
|
|
|
|
@@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
|
|
|
|
|
bare_name = typedef_name;
|
|
|
|
|
name = typedef_name;
|
|
|
|
|
} else {
|
|
|
|
|
if (raw_record_ty.isAnonymousRecord(c.comp)) {
|
|
|
|
|
if (record_ty.isAnonymousRecord(c.comp)) {
|
|
|
|
|
bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
|
|
|
|
|
is_unnamed = true;
|
|
|
|
|
}
|
|
|
|
@@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
|
|
|
|
|
|
|
|
|
|
const is_pub = toplevel and !is_unnamed;
|
|
|
|
|
const init_node = blk: {
|
|
|
|
|
if (record_decl.isIncomplete()) {
|
|
|
|
|
try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {});
|
|
|
|
|
break :blk ZigTag.opaque_literal.init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len);
|
|
|
|
|
defer fields.deinit();
|
|
|
|
|
|
|
|
|
@@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
|
|
|
|
|
// layout, then we can just use a simple `extern` type. If it does have attributes,
|
|
|
|
|
// then we need to inspect the layout and assign an `align` value for each field.
|
|
|
|
|
const has_alignment_attributes = record_decl.field_attributes != null or
|
|
|
|
|
raw_record_ty.hasAttribute(.@"packed") or
|
|
|
|
|
raw_record_ty.hasAttribute(.aligned);
|
|
|
|
|
record_ty.hasAttribute(.@"packed") or
|
|
|
|
|
record_ty.hasAttribute(.aligned);
|
|
|
|
|
const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null;
|
|
|
|
|
|
|
|
|
|
// Iterate over field nodes so that we translate any type decls included in this record decl.
|
|
|
|
|
// TODO: Move this logic into `fn transType()` instead of handling decl translation here.
|
|
|
|
|
for (field_nodes) |field_node| {
|
|
|
|
|
const field_raw_ty = node_types[@intFromEnum(field_node)];
|
|
|
|
|
if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (record_decl.fields, 0..) |field, field_index| {
|
|
|
|
|
const field_loc = field.name_tok;
|
|
|
|
|
|
|
|
|
@@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
|
|
|
|
|
fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void {
|
|
|
|
|
const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
|
|
|
|
|
const fn_ty = raw_ty.canonicalize(.standard);
|
|
|
|
|
const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
|
|
|
|
@@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
|
|
|
|
|
|
|
|
|
|
else => unreachable,
|
|
|
|
|
},
|
|
|
|
|
.is_pub = is_pub,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
return addTopLevelDecl(c, fn_name, proto_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {
|
|
|
|
|
@panic("TODO");
|
|
|
|
|
fn transVarDecl(c: *Context, node: NodeIndex) Error!void {
|
|
|
|
|
const data = c.tree.nodes.items(.data)[@intFromEnum(node)];
|
|
|
|
|
const name = c.tree.tokSlice(data.decl.name);
|
|
|
|
|
return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {
|
|
|
|
|
const node_types = c.tree.nodes.items(.ty);
|
|
|
|
|
const ty = node_types[@intFromEnum(enum_decl)];
|
|
|
|
|
if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_|
|
|
|
|
|
fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void {
|
|
|
|
|
if (c.decl_table.get(@intFromPtr(enum_decl))) |_|
|
|
|
|
|
return; // Avoid processing this decl twice
|
|
|
|
|
const toplevel = scope.id == .root;
|
|
|
|
|
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
|
|
|
|
|
|
|
|
|
var is_unnamed = false;
|
|
|
|
|
var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name);
|
|
|
|
|
var bare_name: []const u8 = c.mapper.lookup(enum_decl.name);
|
|
|
|
|
var name = bare_name;
|
|
|
|
|
if (c.unnamed_typedefs.get(@intFromPtr(ty.data.@"enum"))) |typedef_name| {
|
|
|
|
|
if (c.unnamed_typedefs.get(@intFromPtr(enum_decl))) |typedef_name| {
|
|
|
|
|
bare_name = typedef_name;
|
|
|
|
|
name = typedef_name;
|
|
|
|
|
} else {
|
|
|
|
@@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
|
|
|
|
|
name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
|
|
|
|
|
}
|
|
|
|
|
if (!toplevel) name = try bs.makeMangledName(c, name);
|
|
|
|
|
try c.decl_table.putNoClobber(c.gpa, @intFromPtr(ty.data.@"enum"), name);
|
|
|
|
|
try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl), name);
|
|
|
|
|
|
|
|
|
|
const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: {
|
|
|
|
|
for (ty.data.@"enum".fields, field_nodes) |field, field_node| {
|
|
|
|
|
const enum_type_node = if (!enum_decl.isIncomplete()) blk: {
|
|
|
|
|
for (enum_decl.fields, field_nodes) |field, field_node| {
|
|
|
|
|
var enum_val_name: []const u8 = c.mapper.lookup(field.name);
|
|
|
|
|
if (!toplevel) {
|
|
|
|
|
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:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) {
|
|
|
|
|
break :blk transType(c, scope, enum_decl.tag_ty, .standard, 0) catch |err| switch (err) {
|
|
|
|
|
error.UnsupportedType => {
|
|
|
|
|
return failDecl(c, 0, name, "unable to translate enum integer type", .{});
|
|
|
|
|
},
|
|
|
|
|
else => |e| return e,
|
|
|
|
|
};
|
|
|
|
|
} else blk: {
|
|
|
|
|
try c.opaque_demotes.put(c.gpa, @intFromPtr(ty.data.@"enum"), {});
|
|
|
|
|
try c.opaque_demotes.put(c.gpa, @intFromPtr(enum_decl), {});
|
|
|
|
|
break :blk ZigTag.opaque_literal.init();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn getTypeStr(c: *Context, ty: Type) ![]const u8 {
|
|
|
|
|
var buf: std.ArrayListUnmanaged(u8) = .{};
|
|
|
|
|
defer buf.deinit(c.gpa);
|
|
|
|
|
const w = buf.writer(c.gpa);
|
|
|
|
|
try ty.print(c.mapper, c.comp.langopts, w);
|
|
|
|
|
return c.arena.dupe(u8, buf.items);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {
|
|
|
|
|
const ty = raw_ty.canonicalize(qual_handling);
|
|
|
|
|
if (ty.qual.atomic) {
|
|
|
|
|
const type_name = try getTypeStr(c, ty);
|
|
|
|
|
return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ty.specifier) {
|
|
|
|
|
.void => return ZigTag.type.create(c.arena, "anyopaque"),
|
|
|
|
|
.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
|
|
|
|
|
.long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
|
|
|
|
|
.float80 => return ZigTag.type.create(c.arena, "f80"),
|
|
|
|
|
.float128 => return ZigTag.type.create(c.arena, "f128"),
|
|
|
|
|
.@"enum" => @panic("TODO"),
|
|
|
|
|
.pointer,
|
|
|
|
|
.unspecified_variable_len_array,
|
|
|
|
|
.@"enum" => {
|
|
|
|
|
const enum_decl = ty.data.@"enum";
|
|
|
|
|
var trans_scope = scope;
|
|
|
|
|
if (enum_decl.name != .empty) {
|
|
|
|
|
const decl_name = c.mapper.lookup(enum_decl.name);
|
|
|
|
|
if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base;
|
|
|
|
|
}
|
|
|
|
|
try transEnumDecl(c, trans_scope, enum_decl, &.{});
|
|
|
|
|
return ZigTag.identifier.create(c.arena, c.decl_table.get(@intFromPtr(enum_decl)).?);
|
|
|
|
|
},
|
|
|
|
|
.pointer => {
|
|
|
|
|
const child_type = ty.elemType();
|
|
|
|
|
|
|
|
|
|
const is_fn_proto = child_type.isFunc();
|
|
|
|
|
const is_const = is_fn_proto or child_type.isConst();
|
|
|
|
|
const is_volatile = child_type.qual.@"volatile";
|
|
|
|
|
const elem_type = try transType(c, scope, child_type, qual_handling, source_loc);
|
|
|
|
|
const ptr_info = .{
|
|
|
|
|
.is_const = is_const,
|
|
|
|
|
.is_volatile = is_volatile,
|
|
|
|
|
.elem_type = elem_type,
|
|
|
|
|
};
|
|
|
|
|
if (is_fn_proto or
|
|
|
|
|
typeIsOpaque(c, child_type) or
|
|
|
|
|
typeWasDemotedToOpaque(c, child_type))
|
|
|
|
|
{
|
|
|
|
|
const ptr = try ZigTag.single_pointer.create(c.arena, ptr_info);
|
|
|
|
|
return ZigTag.optional_type.create(c.arena, ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ZigTag.c_pointer.create(c.arena, ptr_info);
|
|
|
|
|
},
|
|
|
|
|
.unspecified_variable_len_array, .incomplete_array => {
|
|
|
|
|
const child_type = ty.elemType();
|
|
|
|
|
const is_const = child_type.qual.@"const";
|
|
|
|
|
const is_volatile = child_type.qual.@"volatile";
|
|
|
|
|
const elem_type = try transType(c, scope, child_type, qual_handling, source_loc);
|
|
|
|
|
|
|
|
|
|
return ZigTag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
|
|
|
|
|
},
|
|
|
|
|
.array,
|
|
|
|
|
.static_array,
|
|
|
|
|
.incomplete_array,
|
|
|
|
|
=> @panic("TODO"),
|
|
|
|
|
=> {
|
|
|
|
|
const size = ty.arrayLen().?;
|
|
|
|
|
const elem_type = try transType(c, scope, ty.elemType(), qual_handling, source_loc);
|
|
|
|
|
return ZigTag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
|
|
|
|
|
},
|
|
|
|
|
.func,
|
|
|
|
|
.var_args_func,
|
|
|
|
|
.old_style_func,
|
|
|
|
@@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
|
|
|
|
|
const name_id = c.mapper.lookup(record_decl.name);
|
|
|
|
|
if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base;
|
|
|
|
|
}
|
|
|
|
|
try transRecordDecl(c, trans_scope, ty);
|
|
|
|
|
const name = c.decl_table.get(@intFromPtr(ty.data.record)).?;
|
|
|
|
|
return ZigTag.identifier.create(c.arena, name);
|
|
|
|
|
},
|
|
|
|
@@ -927,7 +1023,9 @@ fn transFnType(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode {
|
|
|
|
|
return transExpr(c, node, .unused);
|
|
|
|
|
_ = c;
|
|
|
|
|
_ = node;
|
|
|
|
|
return error.UnsupportedTranslation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void {
|
|
|
|
@@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn recordHasBitfield(record: *const Type.Record) bool {
|
|
|
|
|
if (record.isIncomplete()) return false;
|
|
|
|
|
for (record.fields) |field| {
|
|
|
|
|
if (!field.isRegularField()) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn typeIsOpaque(c: *Context, ty: Type) bool {
|
|
|
|
|
return switch (ty.specifier) {
|
|
|
|
|
.void => true,
|
|
|
|
|
.@"struct", .@"union" => recordHasBitfield(ty.getRecord().?),
|
|
|
|
|
.typeof_type => typeIsOpaque(c, ty.data.sub_type.*),
|
|
|
|
|
.typeof_expr => typeIsOpaque(c, ty.data.expr.ty),
|
|
|
|
|
.attributed => typeIsOpaque(c, ty.data.attributed.base),
|
|
|
|
|
else => false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn typeWasDemotedToOpaque(c: *Context, ty: Type) bool {
|
|
|
|
|
switch (ty.specifier) {
|
|
|
|
|
.@"struct", .@"union" => {
|
|
|
|
|
const record = ty.getRecord().?;
|
|
|
|
|
if (c.opaque_demotes.contains(@intFromPtr(record))) return true;
|
|
|
|
|
for (record.fields) |field| {
|
|
|
|
|
if (typeWasDemotedToOpaque(c, field.ty)) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
.@"enum" => return c.opaque_demotes.contains(@intFromPtr(ty.data.@"enum")),
|
|
|
|
|
|
|
|
|
|
.typeof_type => return typeWasDemotedToOpaque(c, ty.data.sub_type.*),
|
|
|
|
|
.typeof_expr => return typeWasDemotedToOpaque(c, ty.data.expr.ty),
|
|
|
|
|
.attributed => return typeWasDemotedToOpaque(c, ty.data.attributed.base),
|
|
|
|
|
else => return false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode {
|
|
|
|
|
var block_scope = try Scope.Block.init(c, scope, false);
|
|
|
|
|
defer block_scope.deinit();
|
|
|
|
|