mirror of
https://github.com/ziglang/zig.git
synced 2026-01-30 19:23:37 +00:00
translate-c: support scoped typedef, enum and record decls
Closes #5256
This commit is contained in:
parent
e2974759dd
commit
d5fecbd0ba
@ -433,13 +433,13 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
|
||||
return visitFnDecl(c, @ptrCast(*const clang.FunctionDecl, decl));
|
||||
},
|
||||
.Typedef => {
|
||||
_ = try transTypeDef(c, @ptrCast(*const clang.TypedefNameDecl, decl), true);
|
||||
try transTypeDef(c, &c.global_scope.base, @ptrCast(*const clang.TypedefNameDecl, decl));
|
||||
},
|
||||
.Enum => {
|
||||
_ = try transEnumDecl(c, @ptrCast(*const clang.EnumDecl, decl));
|
||||
try transEnumDecl(c, &c.global_scope.base, @ptrCast(*const clang.EnumDecl, decl));
|
||||
},
|
||||
.Record => {
|
||||
_ = try transRecordDecl(c, @ptrCast(*const clang.RecordDecl, decl));
|
||||
try transRecordDecl(c, &c.global_scope.base, @ptrCast(*const clang.RecordDecl, decl));
|
||||
},
|
||||
.Var => {
|
||||
return visitVarDecl(c, @ptrCast(*const clang.VarDecl, decl), null);
|
||||
@ -622,11 +622,11 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
|
||||
return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
|
||||
}
|
||||
|
||||
fn transQualTypeMaybeInitialized(c: *Context, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node {
|
||||
fn transQualTypeMaybeInitialized(c: *Context, scope: *Scope, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node {
|
||||
return if (decl_init) |init_expr|
|
||||
transQualTypeInitialized(c, qt, init_expr, loc)
|
||||
transQualTypeInitialized(c, scope, qt, init_expr, loc)
|
||||
else
|
||||
transQualType(c, qt, loc);
|
||||
transQualType(c, scope, qt, loc);
|
||||
}
|
||||
|
||||
/// if mangled_name is not null, this var decl was declared in a block scope.
|
||||
@ -658,7 +658,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
|
||||
var is_extern = storage_class == .Extern and !has_init;
|
||||
var is_export = !is_extern and storage_class != .Static;
|
||||
|
||||
const type_node = transQualTypeMaybeInitialized(c, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
|
||||
const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
|
||||
error.UnsupportedTranslation, error.UnsupportedType => {
|
||||
return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});
|
||||
},
|
||||
@ -733,11 +733,6 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
|
||||
return addTopLevelDecl(c, checked_name, node);
|
||||
}
|
||||
|
||||
fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !Node {
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name);
|
||||
return Tag.identifier.create(c.arena, builtin_name);
|
||||
}
|
||||
|
||||
const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{
|
||||
.{ "uint8_t", "u8" },
|
||||
.{ "int8_t", "i8" },
|
||||
@ -753,42 +748,28 @@ const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{
|
||||
.{ "size_t", "usize" },
|
||||
});
|
||||
|
||||
fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?Node {
|
||||
fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNameDecl) Error!void {
|
||||
if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name|
|
||||
return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice
|
||||
return; // Avoid processing this decl twice
|
||||
const toplevel = scope.id == .root;
|
||||
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
||||
|
||||
const typedef_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
|
||||
const bare_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/3756
|
||||
// TODO https://github.com/ziglang/zig/issues/1802
|
||||
const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ typedef_name, c.getMangle() }) else typedef_name;
|
||||
if (builtin_typedef_map.get(checked_name)) |builtin| {
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
|
||||
return try Tag.identifier.create(c.arena, builtin);
|
||||
var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;
|
||||
if (builtin_typedef_map.get(name)) |builtin| {
|
||||
return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
|
||||
}
|
||||
if (!toplevel) name = try bs.makeMangledName(c, name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
|
||||
|
||||
if (!top_level_visit) {
|
||||
return try Tag.identifier.create(c.arena, checked_name);
|
||||
}
|
||||
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name);
|
||||
const node = (try transCreateNodeTypedef(c, typedef_decl, true, checked_name)) orelse return null;
|
||||
try addTopLevelDecl(c, checked_name, node);
|
||||
return try Tag.identifier.create(c.arena, checked_name);
|
||||
}
|
||||
|
||||
fn transCreateNodeTypedef(
|
||||
c: *Context,
|
||||
typedef_decl: *const clang.TypedefNameDecl,
|
||||
toplevel: bool,
|
||||
checked_name: []const u8,
|
||||
) Error!?Node {
|
||||
const child_qt = typedef_decl.getUnderlyingType();
|
||||
const typedef_loc = typedef_decl.getLocation();
|
||||
const init_node = transQualType(c, child_qt, typedef_loc) catch |err| switch (err) {
|
||||
const init_node = transQualType(c, scope, child_qt, typedef_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try failDecl(c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
|
||||
return null;
|
||||
return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{});
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
};
|
||||
@ -797,17 +778,25 @@ fn transCreateNodeTypedef(
|
||||
payload.* = .{
|
||||
.base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(toplevel)] },
|
||||
.data = .{
|
||||
.name = checked_name,
|
||||
.name = name,
|
||||
.init = init_node,
|
||||
},
|
||||
};
|
||||
return Node.initPayload(&payload.base);
|
||||
const node = Node.initPayload(&payload.base);
|
||||
|
||||
if (toplevel) {
|
||||
try addTopLevelDecl(c, name, node);
|
||||
} else {
|
||||
try scope.appendNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Node {
|
||||
fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {
|
||||
if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|
|
||||
return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice
|
||||
return; // Avoid processing this decl twice
|
||||
const record_loc = record_decl.getLocation();
|
||||
const toplevel = scope.id == .root;
|
||||
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
||||
|
||||
var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
|
||||
var is_unnamed = false;
|
||||
@ -826,14 +815,15 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod
|
||||
} else if (record_decl.isStruct()) {
|
||||
container_kind_name = "struct";
|
||||
} else {
|
||||
try warn(c, &c.global_scope.base, record_loc, "record {s} is not a struct or union", .{bare_name});
|
||||
return null;
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), bare_name);
|
||||
return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});
|
||||
}
|
||||
|
||||
const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
|
||||
var name: []const u8 = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
|
||||
if (!toplevel) name = try bs.makeMangledName(c, name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
|
||||
|
||||
const is_pub = !is_unnamed;
|
||||
const is_pub = toplevel and !is_unnamed;
|
||||
const init_node = blk: {
|
||||
const record_def = record_decl.getDefinition() orelse {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
@ -854,13 +844,13 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod
|
||||
|
||||
if (field_decl.isBitField()) {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, &c.global_scope.base, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
|
||||
try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
}
|
||||
|
||||
if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, &c.global_scope.base, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
|
||||
try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
}
|
||||
|
||||
@ -872,10 +862,10 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod
|
||||
unnamed_field_count += 1;
|
||||
is_anon = true;
|
||||
}
|
||||
const field_type = transQualType(c, field_qt, field_loc) catch |err| switch (err) {
|
||||
const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, &c.global_scope.base, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name });
|
||||
try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name });
|
||||
break :blk Tag.opaque_literal.init();
|
||||
},
|
||||
else => |e| return e,
|
||||
@ -891,7 +881,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod
|
||||
};
|
||||
|
||||
if (is_anon) {
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
|
||||
}
|
||||
|
||||
try fields.append(.{
|
||||
@ -921,16 +911,21 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod
|
||||
},
|
||||
};
|
||||
|
||||
try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
|
||||
if (!is_unnamed)
|
||||
try c.alias_list.append(.{ .alias = bare_name, .name = name });
|
||||
return try Tag.identifier.create(c.arena, name);
|
||||
if (toplevel) {
|
||||
try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
|
||||
if (!is_unnamed)
|
||||
try c.alias_list.append(.{ .alias = bare_name, .name = name });
|
||||
} else {
|
||||
try scope.appendNode(Node.initPayload(&payload.base));
|
||||
}
|
||||
}
|
||||
|
||||
fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
|
||||
fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) Error!void {
|
||||
if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name|
|
||||
return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice
|
||||
return; // Avoid processing this decl twice
|
||||
const enum_loc = enum_decl.getLocation();
|
||||
const toplevel = scope.id == .root;
|
||||
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
||||
|
||||
var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
|
||||
var is_unnamed = false;
|
||||
@ -939,10 +934,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
|
||||
is_unnamed = true;
|
||||
}
|
||||
|
||||
const name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
|
||||
_ = try c.decl_table.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
|
||||
var name: []const u8 = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
|
||||
if (!toplevel) _ = try bs.makeMangledName(c, name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
|
||||
|
||||
const is_pub = !is_unnamed;
|
||||
const is_pub = toplevel and !is_unnamed;
|
||||
var redecls = std.ArrayList(Tag.enum_redecl.Data()).init(c.gpa);
|
||||
defer redecls.deinit();
|
||||
|
||||
const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {
|
||||
var pure_enum = true;
|
||||
@ -968,10 +966,9 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
|
||||
const init_arg_expr = if (int_type.ptr != null and
|
||||
!isCBuiltinType(int_type, .UInt) and
|
||||
!isCBuiltinType(int_type, .Int))
|
||||
transQualType(c, int_type, enum_loc) catch |err| switch (err) {
|
||||
transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
|
||||
return null;
|
||||
return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
|
||||
},
|
||||
else => |e| return e,
|
||||
}
|
||||
@ -1001,11 +998,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
|
||||
|
||||
// In C each enum value is in the global namespace. So we put them there too.
|
||||
// At this point we can rely on the enum emitting successfully.
|
||||
try addTopLevelDecl(c, field_name, try Tag.enum_redecl.create(c.arena, .{
|
||||
try redecls.append(.{
|
||||
.enum_val_name = enum_val_name,
|
||||
.field_name = field_name,
|
||||
.enum_name = name,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
break :blk try Tag.@"enum".create(c.arena, .{
|
||||
@ -1026,10 +1023,25 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
|
||||
},
|
||||
};
|
||||
|
||||
try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
|
||||
if (!is_unnamed)
|
||||
try c.alias_list.append(.{ .alias = bare_name, .name = name });
|
||||
return try Tag.identifier.create(c.arena, name);
|
||||
if (toplevel) {
|
||||
try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
|
||||
if (!is_unnamed)
|
||||
try c.alias_list.append(.{ .alias = bare_name, .name = name });
|
||||
} else {
|
||||
try scope.appendNode(Node.initPayload(&payload.base));
|
||||
}
|
||||
|
||||
for (redecls.items) |redecl| {
|
||||
if (toplevel) {
|
||||
try addTopLevelDecl(c, redecl.field_name, try Tag.pub_enum_redecl.create(c.arena, redecl));
|
||||
} else {
|
||||
try scope.appendNode(try Tag.enum_redecl.create(c.arena, .{
|
||||
.enum_val_name = try bs.makeMangledName(c, redecl.enum_val_name),
|
||||
.field_name = redecl.field_name,
|
||||
.enum_name = redecl.enum_name,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ResultUsed = enum {
|
||||
@ -1251,6 +1263,7 @@ fn transCompoundStmtInline(
|
||||
const end_it = stmt.body_end();
|
||||
while (it != end_it) : (it += 1) {
|
||||
const result = try transStmt(c, parent_scope, it[0], .unused);
|
||||
if (result.tag() == .declaration) continue;
|
||||
try block.statements.append(result);
|
||||
}
|
||||
}
|
||||
@ -1285,7 +1298,7 @@ fn transDeclStmtOne(
|
||||
scope: *Scope,
|
||||
decl: *const clang.Decl,
|
||||
block_scope: *Scope.Block,
|
||||
) TransError!Node {
|
||||
) TransError!void {
|
||||
switch (decl.getKind()) {
|
||||
.Var => {
|
||||
const var_decl = @ptrCast(*const clang.VarDecl, decl);
|
||||
@ -1299,8 +1312,7 @@ fn transDeclStmtOne(
|
||||
.Extern, .Static => {
|
||||
// This is actually a global variable, put it in the global scope and reference it.
|
||||
// `_ = mangled_name;`
|
||||
try visitVarDecl(c, var_decl, mangled_name);
|
||||
return try maybeSuppressResult(c, scope, .unused, try Tag.identifier.create(c.arena, mangled_name));
|
||||
return visitVarDecl(c, var_decl, mangled_name);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -1308,7 +1320,7 @@ fn transDeclStmtOne(
|
||||
const is_const = qual_type.isConstQualified();
|
||||
|
||||
const loc = decl.getLocation();
|
||||
const type_node = try transQualTypeMaybeInitialized(c, qual_type, decl_init, loc);
|
||||
const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc);
|
||||
|
||||
var init_node = if (decl_init) |expr|
|
||||
if (expr.getStmtClass() == .StringLiteralClass)
|
||||
@ -1320,7 +1332,7 @@ fn transDeclStmtOne(
|
||||
if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
|
||||
init_node = try Tag.bool_to_int.create(c.arena, init_node);
|
||||
}
|
||||
return Tag.var_decl.create(c.arena, .{
|
||||
const node = try Tag.var_decl.create(c.arena, .{
|
||||
.is_pub = false,
|
||||
.is_const = is_const,
|
||||
.is_extern = false,
|
||||
@ -1332,18 +1344,16 @@ fn transDeclStmtOne(
|
||||
.type = type_node,
|
||||
.init = init_node,
|
||||
});
|
||||
try block_scope.statements.append(node);
|
||||
},
|
||||
.Typedef => {
|
||||
const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);
|
||||
const name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
|
||||
|
||||
const underlying_qual = typedef_decl.getUnderlyingType();
|
||||
const underlying_type = underlying_qual.getTypePtr();
|
||||
|
||||
const mangled_name = try block_scope.makeMangledName(c, name);
|
||||
const node = (try transCreateNodeTypedef(c, typedef_decl, false, mangled_name)) orelse
|
||||
return error.UnsupportedTranslation;
|
||||
return node;
|
||||
try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));
|
||||
},
|
||||
.Record => {
|
||||
try transRecordDecl(c, scope, @ptrCast(*const clang.RecordDecl, decl));
|
||||
},
|
||||
.Enum => {
|
||||
try transEnumDecl(c, scope, @ptrCast(*const clang.EnumDecl, decl));
|
||||
},
|
||||
else => |kind| return fail(
|
||||
c,
|
||||
@ -1356,21 +1366,14 @@ fn transDeclStmtOne(
|
||||
}
|
||||
|
||||
fn transDeclStmt(c: *Context, scope: *Scope, stmt: *const clang.DeclStmt) TransError!Node {
|
||||
const block_scope = scope.findBlockScope(c) catch unreachable;
|
||||
const block_scope = try scope.findBlockScope(c);
|
||||
|
||||
var it = stmt.decl_begin();
|
||||
const end_it = stmt.decl_end();
|
||||
assert(it != end_it);
|
||||
while (true) : (it += 1) {
|
||||
const node = try transDeclStmtOne(c, scope, it[0], block_scope);
|
||||
|
||||
if (it + 1 == end_it) {
|
||||
return node;
|
||||
} else {
|
||||
try block_scope.statements.append(node);
|
||||
}
|
||||
while (it != end_it) : (it += 1) {
|
||||
try transDeclStmtOne(c, scope, it[0], block_scope);
|
||||
}
|
||||
unreachable;
|
||||
return Tag.declaration.init();
|
||||
}
|
||||
|
||||
fn transDeclRefExpr(
|
||||
@ -1619,7 +1622,7 @@ fn transIntegerLiteral(
|
||||
|
||||
// @as(T, x)
|
||||
const expr_base = @ptrCast(*const clang.Expr, expr);
|
||||
const ty_node = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc());
|
||||
const ty_node = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc());
|
||||
const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
|
||||
const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
|
||||
return maybeSuppressResult(c, scope, result_used, as);
|
||||
@ -1697,7 +1700,7 @@ fn transStringLiteralAsArray(
|
||||
const ty = expr_base.getType().getTypePtr();
|
||||
const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
|
||||
|
||||
const elem_type = try transQualType(c, const_arr_ty.getElementType(), expr_base.getBeginLoc());
|
||||
const elem_type = try transQualType(c, scope, const_arr_ty.getElementType(), expr_base.getBeginLoc());
|
||||
const arr_type = try Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_type });
|
||||
const init_list = try c.arena.alloc(Node, array_size);
|
||||
|
||||
@ -1744,9 +1747,9 @@ fn transCCast(
|
||||
if (qualTypeCanon(dst_type).isVoidType()) return expr;
|
||||
if (dst_type.eq(src_type)) return expr;
|
||||
if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
|
||||
return transCPtrCast(c, loc, dst_type, src_type, expr);
|
||||
return transCPtrCast(c, scope, loc, dst_type, src_type, expr);
|
||||
|
||||
const dst_node = try transQualType(c, dst_type, loc);
|
||||
const dst_node = try transQualType(c, scope, dst_type, loc);
|
||||
if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
|
||||
// 1. If src_type is an enum, determine the underlying signed int type
|
||||
// 2. Extend or truncate without changing signed-ness.
|
||||
@ -1903,7 +1906,7 @@ fn transInitListExprRecord(
|
||||
const record_def = record_decl.getDefinition() orelse
|
||||
unreachable;
|
||||
|
||||
const ty_node = try transType(c, ty, loc);
|
||||
const ty_node = try transType(c, scope, ty, loc);
|
||||
const init_count = expr.getNumInits();
|
||||
var field_inits = std.ArrayList(ast.Payload.ContainerInit.Initializer).init(c.gpa);
|
||||
defer field_inits.deinit();
|
||||
@ -1952,7 +1955,7 @@ fn transInitListExprArray(
|
||||
) TransError!Node {
|
||||
const arr_type = ty.getAsArrayTypeUnsafe();
|
||||
const child_qt = arr_type.getElementType();
|
||||
const child_type = try transQualType(c, child_qt, loc);
|
||||
const child_type = try transQualType(c, scope, child_qt, loc);
|
||||
const init_count = expr.getNumInits();
|
||||
assert(@ptrCast(*const clang.Type, arr_type).isConstantArrayType());
|
||||
const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, arr_type);
|
||||
@ -2217,7 +2220,7 @@ fn transForLoop(
|
||||
block_scope = try Scope.Block.init(c, scope, false);
|
||||
loop_scope.parent = &block_scope.?.base;
|
||||
const init_node = try transStmt(c, &block_scope.?.base, init, .unused);
|
||||
try block_scope.?.statements.append(init_node);
|
||||
if (init_node.tag() != .declaration) try block_scope.?.statements.append(init_node);
|
||||
}
|
||||
var cond_scope = Scope.Condition{
|
||||
.base = .{
|
||||
@ -2328,7 +2331,7 @@ fn transCase(
|
||||
scope: *Scope,
|
||||
stmt: *const clang.CaseStmt,
|
||||
) TransError!Node {
|
||||
const block_scope = scope.findBlockScope(c) catch unreachable;
|
||||
const block_scope = try scope.findBlockScope(c);
|
||||
const switch_scope = scope.getSwitch();
|
||||
const label = try block_scope.makeMangledName(c, "case");
|
||||
|
||||
@ -2366,7 +2369,7 @@ fn transDefault(
|
||||
scope: *Scope,
|
||||
stmt: *const clang.DefaultStmt,
|
||||
) TransError!Node {
|
||||
const block_scope = scope.findBlockScope(c) catch unreachable;
|
||||
const block_scope = try scope.findBlockScope(c);
|
||||
const switch_scope = scope.getSwitch();
|
||||
switch_scope.default_label = try block_scope.makeMangledName(c, "default");
|
||||
|
||||
@ -2400,7 +2403,7 @@ fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used:
|
||||
// @as(T, x)
|
||||
const expr_base = @ptrCast(*const clang.Expr, expr);
|
||||
const as_node = try Tag.as.create(c.arena, .{
|
||||
.lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()),
|
||||
.lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
|
||||
.rhs = try transCreateNodeAPInt(c, result.Val.getInt()),
|
||||
});
|
||||
return maybeSuppressResult(c, scope, used, as_node);
|
||||
@ -2446,7 +2449,7 @@ fn transCharLiteral(
|
||||
// @as(T, x)
|
||||
const expr_base = @ptrCast(*const clang.Expr, stmt);
|
||||
const as_node = try Tag.as.create(c.arena, .{
|
||||
.lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()),
|
||||
.lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
|
||||
.rhs = int_lit_node,
|
||||
});
|
||||
return maybeSuppressResult(c, scope, result_used, as_node);
|
||||
@ -2464,6 +2467,7 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
|
||||
const end_it = comp.body_end();
|
||||
while (it != end_it - 1) : (it += 1) {
|
||||
const result = try transStmt(c, &block_scope.base, it[0], .unused);
|
||||
if (result.tag() == .declaration) continue;
|
||||
try block_scope.statements.append(result);
|
||||
}
|
||||
const break_node = try Tag.break_val.create(c.arena, .{
|
||||
@ -2657,7 +2661,7 @@ fn transUnaryExprOrTypeTraitExpr(
|
||||
result_used: ResultUsed,
|
||||
) TransError!Node {
|
||||
const loc = stmt.getBeginLoc();
|
||||
const type_node = try transQualType(c, stmt.getTypeOfArgument(), loc);
|
||||
const type_node = try transQualType(c, scope, stmt.getTypeOfArgument(), loc);
|
||||
|
||||
const kind = stmt.getKind();
|
||||
switch (kind) {
|
||||
@ -2917,9 +2921,9 @@ fn transCreateCompoundAssign(
|
||||
if (is_shift or requires_int_cast) {
|
||||
// @intCast(rhs)
|
||||
const cast_to_type = if (is_shift)
|
||||
try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc)
|
||||
try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
|
||||
else
|
||||
try transQualType(c, getExprQualType(c, lhs), loc);
|
||||
try transQualType(c, scope, getExprQualType(c, lhs), loc);
|
||||
|
||||
rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
|
||||
}
|
||||
@ -2960,9 +2964,9 @@ fn transCreateCompoundAssign(
|
||||
if (is_shift or requires_int_cast) {
|
||||
// @intCast(rhs)
|
||||
const cast_to_type = if (is_shift)
|
||||
try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc)
|
||||
try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
|
||||
else
|
||||
try transQualType(c, getExprQualType(c, lhs), loc);
|
||||
try transQualType(c, scope, getExprQualType(c, lhs), loc);
|
||||
|
||||
rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
|
||||
}
|
||||
@ -2981,6 +2985,7 @@ fn transCreateCompoundAssign(
|
||||
|
||||
fn transCPtrCast(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
loc: clang.SourceLocation,
|
||||
dst_type: clang.QualType,
|
||||
src_type: clang.QualType,
|
||||
@ -2990,7 +2995,7 @@ fn transCPtrCast(
|
||||
const child_type = ty.getPointeeType();
|
||||
const src_ty = src_type.getTypePtr();
|
||||
const src_child_type = src_ty.getPointeeType();
|
||||
const dst_type_node = try transType(c, ty, loc);
|
||||
const dst_type_node = try transType(c, scope, ty, loc);
|
||||
|
||||
if ((src_child_type.isConstQualified() and
|
||||
!child_type.isConstQualified()) or
|
||||
@ -3011,7 +3016,7 @@ fn transCPtrCast(
|
||||
// For opaque types a ptrCast is enough
|
||||
expr
|
||||
else blk: {
|
||||
const child_type_node = try transQualType(c, child_type, loc);
|
||||
const child_type_node = try transQualType(c, scope, child_type, loc);
|
||||
const alignof = try Tag.alignof.create(c.arena, child_type_node);
|
||||
const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
|
||||
break :blk align_cast;
|
||||
@ -3160,6 +3165,7 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
|
||||
/// by the size of the initializer
|
||||
fn transQualTypeInitialized(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
qt: clang.QualType,
|
||||
decl_init: *const clang.Expr,
|
||||
source_loc: clang.SourceLocation,
|
||||
@ -3167,7 +3173,7 @@ fn transQualTypeInitialized(
|
||||
const ty = qt.getTypePtr();
|
||||
if (ty.getTypeClass() == .IncompleteArray) {
|
||||
const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
|
||||
const elem_ty = try transType(c, incomplete_array_ty.getElementType().getTypePtr(), source_loc);
|
||||
const elem_ty = try transType(c, scope, incomplete_array_ty.getElementType().getTypePtr(), source_loc);
|
||||
|
||||
switch (decl_init.getStmtClass()) {
|
||||
.StringLiteralClass => {
|
||||
@ -3184,11 +3190,11 @@ fn transQualTypeInitialized(
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
return transQualType(c, qt, source_loc);
|
||||
return transQualType(c, scope, qt, source_loc);
|
||||
}
|
||||
|
||||
fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
|
||||
return transType(c, qt.getTypePtr(), source_loc);
|
||||
fn transQualType(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
|
||||
return transType(c, scope, qt.getTypePtr(), source_loc);
|
||||
}
|
||||
|
||||
/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
|
||||
@ -3273,7 +3279,7 @@ fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType) !u32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
|
||||
fn qualTypeToLog2IntRef(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
|
||||
const int_bit_width = try qualTypeIntBitWidth(c, qt);
|
||||
|
||||
if (int_bit_width != 0) {
|
||||
@ -3282,7 +3288,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc
|
||||
return Tag.log2_int_type.create(c.arena, cast_bit_width);
|
||||
}
|
||||
|
||||
const zig_type = try transQualType(c, qt, source_loc);
|
||||
const zig_type = try transQualType(c, scope, qt, source_loc);
|
||||
return Tag.std_math_Log2Int.create(c.arena, zig_type);
|
||||
}
|
||||
|
||||
@ -3641,14 +3647,14 @@ fn transCreateNodeShiftOp(
|
||||
|
||||
const lhs = try transExpr(c, scope, lhs_expr, .used);
|
||||
|
||||
const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location);
|
||||
const rhs_type = try qualTypeToLog2IntRef(c, scope, stmt.getType(), rhs_location);
|
||||
const rhs = try transExprCoercing(c, scope, rhs_expr, .used);
|
||||
const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });
|
||||
|
||||
return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);
|
||||
}
|
||||
|
||||
fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
|
||||
fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
|
||||
switch (ty.getTypeClass()) {
|
||||
.Builtin => {
|
||||
const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
|
||||
@ -3687,16 +3693,16 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
|
||||
},
|
||||
.Paren => {
|
||||
const paren_ty = @ptrCast(*const clang.ParenType, ty);
|
||||
return transQualType(c, paren_ty.getInnerType(), source_loc);
|
||||
return transQualType(c, scope, paren_ty.getInnerType(), source_loc);
|
||||
},
|
||||
.Pointer => {
|
||||
const child_qt = ty.getPointeeType();
|
||||
if (qualTypeChildIsFnProto(child_qt)) {
|
||||
return Tag.optional_type.create(c.arena, try transQualType(c, child_qt, source_loc));
|
||||
return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));
|
||||
}
|
||||
const is_const = child_qt.isConstQualified();
|
||||
const is_volatile = child_qt.isVolatileQualified();
|
||||
const elem_type = try transQualType(c, child_qt, source_loc);
|
||||
const elem_type = try transQualType(c, scope, child_qt, source_loc);
|
||||
if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) {
|
||||
const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
|
||||
return Tag.optional_type.create(c.arena, ptr);
|
||||
@ -3709,7 +3715,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
|
||||
|
||||
const size_ap_int = const_arr_ty.getSize();
|
||||
const size = size_ap_int.getLimitedValue(math.maxInt(usize));
|
||||
const elem_type = try transType(c, const_arr_ty.getElementType().getTypePtr(), source_loc);
|
||||
const elem_type = try transType(c, scope, const_arr_ty.getElementType().getTypePtr(), source_loc);
|
||||
|
||||
return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
|
||||
},
|
||||
@ -3719,7 +3725,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
|
||||
const child_qt = incomplete_array_ty.getElementType();
|
||||
const is_const = child_qt.isConstQualified();
|
||||
const is_volatile = child_qt.isVolatileQualified();
|
||||
const elem_type = try transQualType(c, child_qt, source_loc);
|
||||
const elem_type = try transQualType(c, scope, child_qt, source_loc);
|
||||
|
||||
return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
|
||||
},
|
||||
@ -3727,38 +3733,41 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
|
||||
const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
|
||||
|
||||
const typedef_decl = typedef_ty.getDecl();
|
||||
return (try transTypeDef(c, typedef_decl, false)) orelse
|
||||
fail(c, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
|
||||
try transTypeDef(c, scope, typedef_decl);
|
||||
const name = c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl())).?;
|
||||
return Tag.identifier.create(c.arena, name);
|
||||
},
|
||||
.Record => {
|
||||
const record_ty = @ptrCast(*const clang.RecordType, ty);
|
||||
|
||||
const record_decl = record_ty.getDecl();
|
||||
return (try transRecordDecl(c, record_decl)) orelse
|
||||
fail(c, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
|
||||
try transRecordDecl(c, scope, record_decl);
|
||||
const name = c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl())).?;
|
||||
return Tag.identifier.create(c.arena, name);
|
||||
},
|
||||
.Enum => {
|
||||
const enum_ty = @ptrCast(*const clang.EnumType, ty);
|
||||
|
||||
const enum_decl = enum_ty.getDecl();
|
||||
return (try transEnumDecl(c, enum_decl)) orelse
|
||||
fail(c, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
|
||||
try transEnumDecl(c, scope, enum_decl);
|
||||
const name = c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl())).?;
|
||||
return Tag.identifier.create(c.arena, name);
|
||||
},
|
||||
.Elaborated => {
|
||||
const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
|
||||
return transQualType(c, elaborated_ty.getNamedType(), source_loc);
|
||||
return transQualType(c, scope, elaborated_ty.getNamedType(), source_loc);
|
||||
},
|
||||
.Decayed => {
|
||||
const decayed_ty = @ptrCast(*const clang.DecayedType, ty);
|
||||
return transQualType(c, decayed_ty.getDecayedType(), source_loc);
|
||||
return transQualType(c, scope, decayed_ty.getDecayedType(), source_loc);
|
||||
},
|
||||
.Attributed => {
|
||||
const attributed_ty = @ptrCast(*const clang.AttributedType, ty);
|
||||
return transQualType(c, attributed_ty.getEquivalentType(), source_loc);
|
||||
return transQualType(c, scope, attributed_ty.getEquivalentType(), source_loc);
|
||||
},
|
||||
.MacroQualified => {
|
||||
const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty);
|
||||
return transQualType(c, macroqualified_ty.getModifiedType(), source_loc);
|
||||
return transQualType(c, scope, macroqualified_ty.getModifiedType(), source_loc);
|
||||
},
|
||||
else => {
|
||||
const type_name = c.str(ty.getTypeClassName());
|
||||
@ -3890,6 +3899,7 @@ fn finishTransFnProto(
|
||||
) !*ast.Payload.Func {
|
||||
const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
|
||||
const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
|
||||
const scope = &c.global_scope.base;
|
||||
|
||||
// TODO check for always_inline attribute
|
||||
// TODO check for align attribute
|
||||
@ -3914,7 +3924,7 @@ fn finishTransFnProto(
|
||||
|
||||
break :blk param_name;
|
||||
} else null;
|
||||
const type_node = try transQualType(c, param_qt, source_loc);
|
||||
const type_node = try transQualType(c, scope, param_qt, source_loc);
|
||||
|
||||
fn_params.addOneAssumeCapacity().* = .{
|
||||
.is_noalias = is_noalias,
|
||||
@ -3955,9 +3965,9 @@ fn finishTransFnProto(
|
||||
// convert primitive c_void to actual void (only for return type)
|
||||
break :blk Tag.void_type.init();
|
||||
} else {
|
||||
break :blk transQualType(c, return_qt, source_loc) catch |err| switch (err) {
|
||||
break :blk transQualType(c, scope, return_qt, source_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try warn(c, &c.global_scope.base, source_loc, "unsupported function proto return type", .{});
|
||||
try warn(c, scope, source_loc, "unsupported function proto return type", .{});
|
||||
return err;
|
||||
},
|
||||
error.OutOfMemory => |e| return e,
|
||||
|
||||
@ -14,6 +14,8 @@ pub const Node = extern union {
|
||||
ptr_otherwise: *Payload,
|
||||
|
||||
pub const Tag = enum {
|
||||
/// Declarations add themselves to the correct scopes and should not be emitted as this tag.
|
||||
declaration,
|
||||
null_literal,
|
||||
undefined_literal,
|
||||
/// opaque {}
|
||||
@ -186,6 +188,7 @@ pub const Node = extern union {
|
||||
/// pub const name = init;
|
||||
pub_var_simple,
|
||||
/// pub const enum_field_name = @enumToInt(enum_name.field_name);
|
||||
pub_enum_redecl,
|
||||
enum_redecl,
|
||||
|
||||
/// pub inline fn name(params) return_type body
|
||||
@ -201,6 +204,7 @@ pub const Node = extern union {
|
||||
|
||||
pub fn Type(comptime t: Tag) type {
|
||||
return switch (t) {
|
||||
.declaration,
|
||||
.null_literal,
|
||||
.undefined_literal,
|
||||
.opaque_literal,
|
||||
@ -325,7 +329,7 @@ pub const Node = extern union {
|
||||
.arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
|
||||
.log2_int_type => Payload.Log2IntType,
|
||||
.var_simple, .pub_var_simple => Payload.SimpleVarDecl,
|
||||
.enum_redecl => Payload.EnumRedecl,
|
||||
.pub_enum_redecl, .enum_redecl => Payload.EnumRedecl,
|
||||
.array_filler => Payload.ArrayFiller,
|
||||
.pub_inline_fn => Payload.PubInlineFn,
|
||||
.field_access => Payload.FieldAccess,
|
||||
@ -742,6 +746,7 @@ fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange {
|
||||
|
||||
fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
switch (node.tag()) {
|
||||
.declaration => unreachable,
|
||||
.warning => {
|
||||
const payload = node.castTag(.warning).?.data;
|
||||
try c.buf.appendSlice(payload);
|
||||
@ -1585,9 +1590,9 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
},
|
||||
});
|
||||
},
|
||||
.enum_redecl => {
|
||||
const payload = node.castTag(.enum_redecl).?.data;
|
||||
_ = try c.addToken(.keyword_pub, "pub");
|
||||
.pub_enum_redecl, .enum_redecl => {
|
||||
const payload = @fieldParentPtr(Payload.EnumRedecl, "base", node.ptr_otherwise).data;
|
||||
if (node.tag() == .pub_enum_redecl) _ = try c.addToken(.keyword_pub, "pub");
|
||||
const const_tok = try c.addToken(.keyword_const, "const");
|
||||
_ = try c.addIdentifier(payload.enum_val_name);
|
||||
_ = try c.addToken(.equal, "=");
|
||||
@ -1878,6 +1883,7 @@ fn addSemicolonIfNotBlock(c: *Context, node: Node) !void {
|
||||
|
||||
fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
switch (node.tag()) {
|
||||
.declaration => unreachable,
|
||||
.null_literal,
|
||||
.undefined_literal,
|
||||
.true_literal,
|
||||
@ -1991,6 +1997,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.alias,
|
||||
.var_simple,
|
||||
.pub_var_simple,
|
||||
.pub_enum_redecl,
|
||||
.enum_redecl,
|
||||
.@"while",
|
||||
.@"switch",
|
||||
|
||||
@ -3,6 +3,136 @@ const std = @import("std");
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("scoped enum",
|
||||
\\void foo() {
|
||||
\\ enum Foo {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\ };
|
||||
\\ enum Foo a = B;
|
||||
\\ {
|
||||
\\ enum Foo {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\ };
|
||||
\\ enum Foo a = B;
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ const enum_Foo = extern enum(c_int) {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\ _,
|
||||
\\ };
|
||||
\\ const A = @enumToInt(enum_Foo.A);
|
||||
\\ const B = @enumToInt(enum_Foo.B);
|
||||
\\ const C = @enumToInt(enum_Foo.C);
|
||||
\\ var a: enum_Foo = @intToEnum(enum_Foo, B);
|
||||
\\ {
|
||||
\\ const enum_Foo = extern enum(c_int) {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\ _,
|
||||
\\ };
|
||||
\\ const A_2 = @enumToInt(enum_Foo.A);
|
||||
\\ const B_3 = @enumToInt(enum_Foo.B);
|
||||
\\ const C_4 = @enumToInt(enum_Foo.C);
|
||||
\\ var a_5: enum_Foo = @intToEnum(enum_Foo, B_3);
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("scoped record",
|
||||
\\void foo() {
|
||||
\\ struct Foo {
|
||||
\\ int A;
|
||||
\\ int B;
|
||||
\\ int C;
|
||||
\\ };
|
||||
\\ struct Foo a = {0};
|
||||
\\ {
|
||||
\\ struct Foo {
|
||||
\\ int A;
|
||||
\\ int B;
|
||||
\\ int C;
|
||||
\\ };
|
||||
\\ struct Foo a = {0};
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ const struct_Foo = extern struct {
|
||||
\\ A: c_int,
|
||||
\\ B: c_int,
|
||||
\\ C: c_int,
|
||||
\\ };
|
||||
\\ var a: struct_Foo = struct_Foo{
|
||||
\\ .A = @as(c_int, 0),
|
||||
\\ .B = 0,
|
||||
\\ .C = 0,
|
||||
\\ };
|
||||
\\ {
|
||||
\\ const struct_Foo_1 = extern struct {
|
||||
\\ A: c_int,
|
||||
\\ B: c_int,
|
||||
\\ C: c_int,
|
||||
\\ };
|
||||
\\ var a_2: struct_Foo_1 = struct_Foo_1{
|
||||
\\ .A = @as(c_int, 0),
|
||||
\\ .B = 0,
|
||||
\\ .C = 0,
|
||||
\\ };
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("scoped typedef",
|
||||
\\void foo() {
|
||||
\\ typedef union {
|
||||
\\ int A;
|
||||
\\ int B;
|
||||
\\ int C;
|
||||
\\ } Foo;
|
||||
\\ Foo a = {0};
|
||||
\\ {
|
||||
\\ typedef union {
|
||||
\\ int A;
|
||||
\\ int B;
|
||||
\\ int C;
|
||||
\\ } Foo;
|
||||
\\ Foo a = {0};
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ const union_unnamed_1 = extern union {
|
||||
\\ A: c_int,
|
||||
\\ B: c_int,
|
||||
\\ C: c_int,
|
||||
\\ };
|
||||
\\ const Foo = union_unnamed_1;
|
||||
\\ var a: Foo = Foo{
|
||||
\\ .A = @as(c_int, 0),
|
||||
\\ };
|
||||
\\ {
|
||||
\\ const union_unnamed_2 = extern union {
|
||||
\\ A: c_int,
|
||||
\\ B: c_int,
|
||||
\\ C: c_int,
|
||||
\\ };
|
||||
\\ const Foo_1 = union_unnamed_2;
|
||||
\\ var a_2: Foo_1 = Foo_1{
|
||||
\\ .A = @as(c_int, 0),
|
||||
\\ };
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("use cast param as macro fn return type",
|
||||
\\#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED)
|
||||
, &[_][]const u8{
|
||||
@ -62,7 +192,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export var bar: f32 = @import("std").mem.zeroes(f32);
|
||||
\\threadlocal var bar_1: c_int = 2;
|
||||
\\pub export fn foo() c_int {
|
||||
\\ _ = bar_1;
|
||||
\\ return 0;
|
||||
\\}
|
||||
});
|
||||
@ -579,9 +708,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ '2',
|
||||
\\ 0,
|
||||
\\};
|
||||
\\pub export fn foo() void {
|
||||
\\ _ = v2;
|
||||
\\}
|
||||
\\pub export fn foo() void {}
|
||||
});
|
||||
|
||||
cases.add("simple function definition",
|
||||
@ -1355,11 +1482,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\extern enum enum_ty my_enum;
|
||||
\\enum enum_ty { FOO };
|
||||
, &[_][]const u8{
|
||||
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
|
||||
\\pub const enum_enum_ty = extern enum(c_int) {
|
||||
\\ FOO,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
|
||||
\\pub extern var my_enum: enum_enum_ty;
|
||||
});
|
||||
|
||||
@ -1501,48 +1628,48 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ p,
|
||||
\\};
|
||||
, &[_][]const u8{
|
||||
\\pub const a = @enumToInt(enum_unnamed_1.a);
|
||||
\\pub const b = @enumToInt(enum_unnamed_1.b);
|
||||
\\pub const c = @enumToInt(enum_unnamed_1.c);
|
||||
\\const enum_unnamed_1 = extern enum(c_int) {
|
||||
\\ a,
|
||||
\\ b,
|
||||
\\ c,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const a = @enumToInt(enum_unnamed_1.a);
|
||||
\\pub const b = @enumToInt(enum_unnamed_1.b);
|
||||
\\pub const c = @enumToInt(enum_unnamed_1.c);
|
||||
\\pub const d = enum_unnamed_1;
|
||||
\\pub const e = @enumToInt(enum_unnamed_2.e);
|
||||
\\pub const f = @enumToInt(enum_unnamed_2.f);
|
||||
\\pub const g = @enumToInt(enum_unnamed_2.g);
|
||||
\\const enum_unnamed_2 = extern enum(c_int) {
|
||||
\\ e = 0,
|
||||
\\ f = 4,
|
||||
\\ g = 5,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const e = @enumToInt(enum_unnamed_2.e);
|
||||
\\pub const f = @enumToInt(enum_unnamed_2.f);
|
||||
\\pub const g = @enumToInt(enum_unnamed_2.g);
|
||||
\\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
|
||||
\\pub const i = @enumToInt(enum_unnamed_3.i);
|
||||
\\pub const j = @enumToInt(enum_unnamed_3.j);
|
||||
\\pub const k = @enumToInt(enum_unnamed_3.k);
|
||||
\\const enum_unnamed_3 = extern enum(c_int) {
|
||||
\\ i,
|
||||
\\ j,
|
||||
\\ k,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const i = @enumToInt(enum_unnamed_3.i);
|
||||
\\pub const j = @enumToInt(enum_unnamed_3.j);
|
||||
\\pub const k = @enumToInt(enum_unnamed_3.k);
|
||||
\\pub const struct_Baz = extern struct {
|
||||
\\ l: enum_unnamed_3,
|
||||
\\ m: d,
|
||||
\\};
|
||||
\\pub const n = @enumToInt(enum_i.n);
|
||||
\\pub const o = @enumToInt(enum_i.o);
|
||||
\\pub const p = @enumToInt(enum_i.p);
|
||||
\\pub const enum_i = extern enum(c_int) {
|
||||
\\ n,
|
||||
\\ o,
|
||||
\\ p,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const n = @enumToInt(enum_i.n);
|
||||
\\pub const o = @enumToInt(enum_i.o);
|
||||
\\pub const p = @enumToInt(enum_i.p);
|
||||
,
|
||||
\\pub const Baz = struct_Baz;
|
||||
});
|
||||
@ -1989,13 +2116,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ Two,
|
||||
\\};
|
||||
, &[_][]const u8{
|
||||
\\pub const One = @enumToInt(enum_unnamed_1.One);
|
||||
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
|
||||
\\const enum_unnamed_1 = extern enum(c_int) {
|
||||
\\ One,
|
||||
\\ Two,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const One = @enumToInt(enum_unnamed_1.One);
|
||||
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
|
||||
});
|
||||
|
||||
cases.add("c style cast",
|
||||
@ -2093,15 +2220,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub const FooA = @enumToInt(enum_Foo.A);
|
||||
\\pub const FooB = @enumToInt(enum_Foo.B);
|
||||
\\pub const FooC = @enumToInt(enum_Foo.C);
|
||||
\\pub const enum_Foo = extern enum(c_int) {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const FooA = @enumToInt(enum_Foo.A);
|
||||
\\pub const FooB = @enumToInt(enum_Foo.B);
|
||||
\\pub const FooC = @enumToInt(enum_Foo.C);
|
||||
\\pub const SomeTypedef = c_int;
|
||||
\\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
|
||||
\\ var a = arg_a;
|
||||
@ -2147,6 +2274,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ B,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const BarA = @enumToInt(enum_Bar.A);
|
||||
\\pub const BarB = @enumToInt(enum_Bar.B);
|
||||
\\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
|
||||
,
|
||||
\\pub const Foo = struct_Foo;
|
||||
@ -2413,6 +2542,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ C,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const A = @enumToInt(enum_SomeEnum.A);
|
||||
\\pub const B = @enumToInt(enum_SomeEnum.B);
|
||||
\\pub const C = @enumToInt(enum_SomeEnum.C);
|
||||
\\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
|
||||
\\ var a = arg_a;
|
||||
\\ var b = arg_b;
|
||||
@ -2872,15 +3004,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ Foo1,
|
||||
\\};
|
||||
, &[_][]const u8{
|
||||
\\pub const FooA = @enumToInt(enum_Foo.A);
|
||||
\\pub const FooB = @enumToInt(enum_Foo.B);
|
||||
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
|
||||
\\pub const enum_Foo = extern enum(c_int) {
|
||||
\\ A = 2,
|
||||
\\ B = 5,
|
||||
\\ @"1" = 6,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const FooA = @enumToInt(enum_Foo.A);
|
||||
\\pub const FooB = @enumToInt(enum_Foo.B);
|
||||
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
|
||||
,
|
||||
\\pub const Foo = enum_Foo;
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user