Skip to content

translate-c: Remove usage of extern enum #9164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 2 additions & 35 deletions lib/std/zig/c_translation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const mem = std.mem;

/// Given a type and value, cast the value to the type as c would.
pub fn cast(comptime DestType: type, target: anytype) DestType {
// this function should behave like transCCast in translate-c, except it's for macros and enums
// this function should behave like transCCast in translate-c, except it's for macros
const SourceType = @TypeOf(target);
switch (@typeInfo(DestType)) {
.Fn, .Pointer => return castToPtr(DestType, SourceType, target),
Expand All @@ -20,12 +20,6 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
return castToPtr(DestType, SourceType, target);
}
},
.Enum => |enum_type| {
if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
const intermediate = cast(enum_type.tag_type, target);
return @intToEnum(DestType, intermediate);
}
},
.Int => {
switch (@typeInfo(SourceType)) {
.Pointer => {
Expand All @@ -36,9 +30,6 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
return castInt(DestType, @ptrToInt(target));
}
},
.Enum => {
return castInt(DestType, @enumToInt(target));
},
.Int => {
return castInt(DestType, target);
},
Expand Down Expand Up @@ -106,12 +97,6 @@ fn ptrInfo(comptime PtrType: type) std.builtin.TypeInfo.Pointer {
}

test "cast" {
const E = enum(u2) {
Zero,
One,
Two,
};

var i = @as(i64, 10);

try testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16));
Expand All @@ -122,12 +107,9 @@ test "cast" {
try testing.expect(cast(?*i64, @as(*align(1) i64, &i)) == &i);
try testing.expect(cast(?*i64, @as(?*align(1) i64, &i)) == &i);

try testing.expect(cast(E, 1) == .One);

try testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(*u32, 4)));
try testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4)));
try testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10)));
try testing.expectEqual(@as(u8, 2), cast(u8, E.Two));

try testing.expectEqual(@bitCast(i32, @as(u32, 0x8000_0000)), cast(i32, @as(u32, 0x8000_0000)));

Expand All @@ -136,17 +118,6 @@ test "cast" {

try testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2)));

const C_ENUM = enum(c_int) {
A = 0,
B,
C,
_,
};
try testing.expectEqual(cast(C_ENUM, @as(i64, -1)), @intToEnum(C_ENUM, -1));
try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
try testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));

var foo: c_int = -1;
try testing.expect(cast(*c_void, -1) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
try testing.expect(cast(*c_void, foo) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
Expand All @@ -162,7 +133,7 @@ test "cast" {
pub fn sizeof(target: anytype) usize {
const T: type = if (@TypeOf(target) == type) target else @TypeOf(target);
switch (@typeInfo(T)) {
.Float, .Int, .Struct, .Union, .Enum, .Array, .Bool, .Vector => return @sizeOf(T),
.Float, .Int, .Struct, .Union, .Array, .Bool, .Vector => return @sizeOf(T),
.Fn => {
// sizeof(main) returns 1, sizeof(&main) returns pointer size.
// We cannot distinguish those types in Zig, so use pointer size.
Expand Down Expand Up @@ -228,7 +199,6 @@ pub fn sizeof(target: anytype) usize {
}

test "sizeof" {
const E = enum(c_int) { One, _ };
const S = extern struct { a: u32 };

const ptr_size = @sizeOf(*c_void);
Expand All @@ -239,9 +209,6 @@ test "sizeof" {

try testing.expect(sizeof(2.0) == @sizeOf(f64));

try testing.expect(sizeof(E) == @sizeOf(c_int));
try testing.expect(sizeof(E.One) == @sizeOf(c_int));

try testing.expect(sizeof(S) == 4);

try testing.expect(sizeof([_]u32{ 4, 5, 6 }) == 12);
Expand Down
3 changes: 0 additions & 3 deletions src/clang.zig
Original file line number Diff line number Diff line change
Expand Up @@ -389,9 +389,6 @@ pub const ElaboratedType = opaque {
};

pub const EnumConstantDecl = opaque {
pub const getInitExpr = ZigClangEnumConstantDecl_getInitExpr;
extern fn ZigClangEnumConstantDecl_getInitExpr(*const EnumConstantDecl) ?*const Expr;

pub const getInitVal = ZigClangEnumConstantDecl_getInitVal;
extern fn ZigClangEnumConstantDecl_getInitVal(*const EnumConstantDecl) *const APSInt;
};
Expand Down
115 changes: 35 additions & 80 deletions src/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1099,89 +1099,65 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
}
name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
}
if (!toplevel) _ = try bs.makeMangledName(c, name);
if (!toplevel) name = try bs.makeMangledName(c, name);
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);

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;
const enum_type_node = if (enum_decl.getDefinition()) |enum_def| blk: {
var it = enum_def.enumerator_begin();
var end_it = enum_def.enumerator_end();
const end_it = enum_def.enumerator_end();
while (it.neq(end_it)) : (it = it.next()) {
const enum_const = it.deref();
if (enum_const.getInitExpr()) |_| {
pure_enum = false;
break;
var enum_val_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
if (!toplevel) {
enum_val_name = try bs.makeMangledName(c, enum_val_name);
}
}

var fields = std.ArrayList(ast.Payload.Enum.Field).init(c.gpa);
defer fields.deinit();
const enum_const_qt = @ptrCast(*const clang.ValueDecl, enum_const).getType();
const enum_const_loc = @ptrCast(*const clang.Decl, enum_const).getLocation();
const enum_const_type_node: ?Node = transQualType(c, scope, enum_const_qt, enum_const_loc) catch |err| switch (err) {
error.UnsupportedType => null,
else => |e| return e,
};

const enum_const_def = try Tag.enum_constant.create(c.arena, .{
.name = enum_val_name,
.is_public = toplevel,
.type = enum_const_type_node,
.value = try transCreateNodeAPInt(c, enum_const.getInitVal()),
});
if (toplevel)
try addTopLevelDecl(c, enum_val_name, enum_const_def)
else
try scope.appendNode(enum_const_def);
}

const int_type = enum_decl.getIntegerType();
// The underlying type may be null in case of forward-declared enum
// types, while that's not ISO-C compliant many compilers allow this and
// default to the usual integer type used for all the enums.

// default to c_int since msvc and gcc default to different types
const init_arg_expr = if (int_type.ptr != null)
break :blk if (int_type.ptr != null)
transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
return failDecl(c, enum_loc, name, "unable to translate enum integer type", .{});
},
else => |e| return e,
}
else
try Tag.type.create(c.arena, "c_int");

it = enum_def.enumerator_begin();
end_it = enum_def.enumerator_end();
while (it.neq(end_it)) : (it = it.next()) {
const enum_const = it.deref();
const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());

const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))
enum_val_name[bare_name.len..]
else
enum_val_name;

const int_node = if (!pure_enum)
try transCreateNodeAPInt(c, enum_const.getInitVal())
else
null;

try fields.append(.{
.name = field_name,
.value = int_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 redecls.append(.{
.enum_val_name = enum_val_name,
.field_name = field_name,
.enum_name = name,
});
}

break :blk try Tag.@"enum".create(c.arena, .{
.int_type = init_arg_expr,
.fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
});
} else blk: {
try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
break :blk Tag.opaque_literal.init();
};

const is_pub = toplevel and !is_unnamed;
const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
payload.* = .{
.base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
.data = .{
.init = enum_type_node,
.name = name,
.init = init_node,
},
};

Expand All @@ -1192,18 +1168,6 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
} 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 {
Expand Down Expand Up @@ -2096,8 +2060,7 @@ fn finishBoolExpr(
},
.Enum => {
// node != 0
const int_val = try Tag.enum_to_int.create(c.arena, node);
return Tag.not_equal.create(c.arena, .{ .lhs = int_val, .rhs = Tag.zero_literal.init() });
return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
},
.Elaborated => {
const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
Expand Down Expand Up @@ -2309,21 +2272,22 @@ fn transCCast(
if (dst_type.eq(src_type)) return expr;
if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
return transCPtrCast(c, scope, loc, dst_type, src_type, expr);
if (cIsEnum(dst_type)) return transCCast(c, scope, loc, cIntTypeForEnum(dst_type), src_type, expr);
if (cIsEnum(src_type)) return transCCast(c, scope, loc, dst_type, cIntTypeForEnum(src_type), expr);

const dst_node = try transQualType(c, scope, dst_type, loc);
if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
if (cIsInteger(dst_type) and cIsInteger(src_type)) {
// 1. If src_type is an enum, determine the underlying signed int type
// 2. Extend or truncate without changing signed-ness.
// 3. Bit-cast to correct signed-ness
const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type);
const src_type_is_signed = cIsSignedInteger(src_int_type);
var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, expr);
const src_type_is_signed = cIsSignedInteger(src_type);
var src_int_expr = expr;

if (isBoolRes(src_int_expr)) {
src_int_expr = try Tag.bool_to_int.create(c.arena, src_int_expr);
}

switch (cIntTypeCmp(dst_type, src_int_type)) {
switch (cIntTypeCmp(dst_type, src_type)) {
.lt => {
// @truncate(SameSignSmallerInt, src_int_expr)
const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
Expand Down Expand Up @@ -2376,14 +2340,6 @@ fn transCCast(
const bool_to_int = try Tag.bool_to_int.create(c.arena, expr);
return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
}
if (cIsEnum(dst_type)) {
// import("std").meta.cast(dest_type, val)
return Tag.helpers_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
// @enumToInt(val)
return Tag.enum_to_int.create(c.arena, expr);
}
// @as(dest_type, val)
return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
Expand Down Expand Up @@ -5969,7 +5925,6 @@ fn getContainer(c: *Context, node: Node) ?Node {
switch (node.tag()) {
.@"union",
.@"struct",
.@"enum",
.address_of,
.bit_not,
.not,
Expand Down
Loading