aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2021-02-17 16:26:11 +0200
committerVeikka Tuominen <git@vexu.eu>2021-02-17 16:26:11 +0200
commitd5fecbd0bacd986fc02c8a98aea07ac42303f0ce (patch)
tree95f8bad785c2f41e800a439635b4f57ae4470f8d
parente2974759dd62e15f04e1aeb8babee65e6ffb3413 (diff)
downloadzig-d5fecbd0bacd986fc02c8a98aea07ac42303f0ce.tar.gz
zig-d5fecbd0bacd986fc02c8a98aea07ac42303f0ce.zip
translate-c: support scoped typedef, enum and record decls
Closes #5256
-rw-r--r--src/translate_c.zig290
-rw-r--r--src/translate_c/ast.zig15
-rw-r--r--test/translate_c.zig182
3 files changed, 318 insertions, 169 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 0ab72d7734..5ac60bffae 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -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,
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index 6d22c7a270..25cbe1bf3f 100644
--- a/src/translate_c/ast.zig
+++ b/src/translate_c/ast.zig
@@ -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",
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 79361bf9bf..26d35a4c2e 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -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;
});