translate-c-2 fix container type resolution

master
Vexu 2019-12-17 22:05:07 +02:00
parent 65531c73a9
commit a6960b89ed
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 263 additions and 284 deletions

View File

@ -371,13 +371,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));
},
.Typedef => {
return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
_ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
},
.Enum => {
_ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl));
},
.Record => {
return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
_ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
},
.Var => {
return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
@ -541,10 +541,9 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
return addTopLevelDecl(c, checked_name, &node.base);
}
fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {
if (c.decl_table.contains(
@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)),
)) return; // Avoid processing this decl twice
fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!?*ast.Node {
if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv|
return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const visib_tok = try appendToken(c, .Keyword_pub, "pub");
const const_tok = try appendToken(c, .Keyword_const, "const");
@ -558,29 +557,40 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err
const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
error.UnsupportedType => {
return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
return null;
},
error.OutOfMemory => |e| return e,
};
node.semicolon_token = try appendToken(c, .Semicolon, ";");
try addTopLevelDecl(c, typedef_name, &node.base);
return transCreateNodeIdentifier(c, typedef_name);
}
fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {
if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice
const rp = makeRestorePoint(c);
fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|
return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
const record_loc = ZigClangRecordDecl_getLocation(record_decl);
const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
var is_unnamed = false;
if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) {
bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
"union"
else if (ZigClangRecordDecl_isStruct(record_decl))
"struct"
else
return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
return;
var container_kind_name: []const u8 = undefined;
var container_kind: std.zig.Token.Id = undefined;
if (ZigClangRecordDecl_isUnion(record_decl)) {
container_kind_name = "union";
container_kind = .Keyword_union;
} else if (ZigClangRecordDecl_isStruct(record_decl)) {
container_kind_name = "struct";
container_kind = .Keyword_struct;
} else {
try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name});
return null;
}
const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
@ -588,16 +598,211 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!
const node = try transCreateNodeVarDecl(c, true, true, name);
node.eq_token = try appendToken(c, .Equal, "=");
node.init_node = transRecordDecl(c, record_decl) catch |err| switch (err) {
error.UnsupportedType => {
return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{});
},
error.OutOfMemory => |e| return e,
var semicolon: ast.TokenIndex = undefined;
node.init_node = blk: {
const rp = makeRestorePoint(c);
const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
const opaque = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
break :blk opaque;
};
const extern_tok = try appendToken(c, .Keyword_extern, "extern");
const container_tok = try appendToken(c, container_kind, container_kind_name);
const lbrace_token = try appendToken(c, .LBrace, "{");
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
.lbrace_token = lbrace_token,
.rbrace_token = undefined,
};
var it = ZigClangRecordDecl_field_begin(record_def);
const end_it = ZigClangRecordDecl_field_end(record_def);
while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
const field_loc = ZigClangFieldDecl_getLocation(field_decl);
if (ZigClangFieldDecl_isBitField(field_decl)) {
const opaque = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
break :blk opaque;
}
const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
_ = try appendToken(c, .Colon, ":");
const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name});
return null;
},
else => |e| return e,
};
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = field_name,
.type_expr = field_type,
.value_expr = null,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
}
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
semicolon = try appendToken(c, .Semicolon, ";");
break :blk &container_node.base;
};
node.semicolon_token = semicolon;
try addTopLevelDecl(c, name, &node.base);
if (!is_unnamed)
try c.alias_list.push(.{ .alias = bare_name, .name = name });
return transCreateNodeIdentifier(c, name);
}
fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
var is_unnamed = false;
if (bare_name.len == 0) {
bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
const node = try transCreateNodeVarDecl(c, true, true, name);
node.eq_token = try appendToken(c, .Equal, "=");
node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
var pure_enum = true;
var it = ZigClangEnumDecl_enumerator_begin(enum_def);
var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| {
pure_enum = false;
break;
}
}
const extern_tok = try appendToken(c, .Keyword_extern, "extern");
const container_tok = try appendToken(c, .Keyword_enum, "enum");
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
.lbrace_token = undefined,
.rbrace_token = undefined,
};
const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
{
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
.Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
return null;
},
else => |e| return e,
},
};
_ = try appendToken(c, .RParen, ")");
}
container_node.lbrace_token = try appendToken(c, .LBrace, "{");
it = ZigClangEnumDecl_enumerator_begin(enum_def);
end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const)));
const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name))
enum_val_name[bare_name.len..]
else
enum_val_name;
const field_name_tok = try appendIdentifier(c, field_name);
const int_node = if (!pure_enum) blk: {
_ = try appendToken(c, .Colon, "=");
break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
} else
null;
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = field_name_tok,
.type_expr = null,
.value_expr = int_node,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
// 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 addEnumTopLevel(c, name, field_name, enum_val_name);
}
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
break :blk &container_node.base;
} else
try transCreateNodeOpaqueType(c);
node.semicolon_token = try appendToken(c, .Semicolon, ";");
try addTopLevelDecl(c, name, &node.base);
try c.alias_list.push(.{ .alias = bare_name, .name = name });
if (!is_unnamed)
try c.alias_list.push(.{ .alias = bare_name, .name = name });
return transCreateNodeIdentifier(c, name);
}
fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {
const node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
node.eq_token = try appendToken(c, .Equal, "=");
const enum_ident = try transCreateNodeIdentifier(c, enum_name);
const period_tok = try appendToken(c, .Period, ".");
const field_ident = try transCreateNodeIdentifier(c, field_name);
node.semicolon_token = try appendToken(c, .Semicolon, ";");
const field_access_node = try c.a().create(ast.Node.InfixOp);
field_access_node.* = .{
.op_token = period_tok,
.lhs = enum_ident,
.op = .Period,
.rhs = field_ident,
};
node.init_node = &field_access_node.base;
try addTopLevelDecl(c, field_name, &node.base);
}
fn createAlias(c: *Context, alias: var) !void {
@ -1452,7 +1657,6 @@ fn transSwitch(
switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
return &switch_scope.pending_block.base;
}
fn transCase(
rp: RestorePoint,
@ -1675,222 +1879,6 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou
return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
}
fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node {
const rp = makeRestorePoint(c);
const record_loc = ZigClangRecordDecl_getLocation(record_decl);
var container_kind_name: []const u8 = undefined;
var container_kind: std.zig.Token.Id = undefined;
if (ZigClangRecordDecl_isUnion(record_decl)) {
container_kind_name = "union";
container_kind = .Keyword_union;
} else if (ZigClangRecordDecl_isStruct(record_decl)) {
container_kind_name = "struct";
container_kind = .Keyword_struct;
} else {
return revertAndWarn(
rp,
error.UnsupportedType,
record_loc,
"unsupported record type",
.{},
);
}
const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
return transCreateNodeOpaqueType(c);
};
const extern_tok = try appendToken(c, .Keyword_extern, "extern");
const container_tok = try appendToken(c, container_kind, container_kind_name);
const lbrace_token = try appendToken(c, .LBrace, "{");
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
.lbrace_token = lbrace_token,
.rbrace_token = undefined,
};
var it = ZigClangRecordDecl_field_begin(record_def);
const end_it = ZigClangRecordDecl_field_end(record_def);
while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
const field_loc = ZigClangFieldDecl_getLocation(field_decl);
if (ZigClangFieldDecl_isBitField(field_decl)) {
rp.activate();
const node = try transCreateNodeOpaqueType(c);
try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
return node;
}
const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
_ = try appendToken(c, .Colon, ":");
const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc);
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = field_name,
.type_expr = field_type,
.value_expr = null,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
}
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
return &container_node.base;
}
fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
const rp = makeRestorePoint(c);
const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
var is_unnamed = false;
if (bare_name.len == 0) {
bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
const node = try transCreateNodeVarDecl(c, true, true, name);
node.eq_token = try appendToken(c, .Equal, "=");
node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
var pure_enum = true;
var it = ZigClangEnumDecl_enumerator_begin(enum_def);
var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| {
pure_enum = false;
break;
}
}
const extern_tok = try appendToken(c, .Keyword_extern, "extern");
const container_tok = try appendToken(c, .Keyword_enum, "enum");
const container_node = try c.a().create(ast.Node.ContainerDecl);
container_node.* = .{
.layout_token = extern_tok,
.kind_token = container_tok,
.init_arg_expr = .None,
.fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
.lbrace_token = undefined,
.rbrace_token = undefined,
};
const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
{
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
.Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
if (is_unnamed) {
try emitWarning(c, enum_loc, "unable to translate enum tag type", .{});
} else {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
}
return null;
},
else => |e| return e,
},
};
_ = try appendToken(c, .RParen, ")");
}
container_node.lbrace_token = try appendToken(c, .LBrace, "{");
it = ZigClangEnumDecl_enumerator_begin(enum_def);
end_it = ZigClangEnumDecl_enumerator_end(enum_def);
while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const)));
const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name))
enum_val_name[bare_name.len..]
else
enum_val_name;
const field_name_tok = try appendIdentifier(c, field_name);
const int_node = if (!pure_enum) blk: {
_ = try appendToken(c, .Colon, "=");
break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
} else
null;
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = field_name_tok,
.type_expr = null,
.value_expr = int_node,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
// 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 addEnumTopLevel(c, name, field_name, enum_val_name);
}
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
break :blk &container_node.base;
} else
try transCreateNodeOpaqueType(c);
node.semicolon_token = try appendToken(c, .Semicolon, ";");
try addTopLevelDecl(c, name, &node.base);
if (!is_unnamed)
try c.alias_list.push(.{ .alias = bare_name, .name = name });
return transCreateNodeIdentifier(c, name);
}
fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {
const node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
node.eq_token = try appendToken(c, .Equal, "=");
const enum_ident = try transCreateNodeIdentifier(c, enum_name);
const period_tok = try appendToken(c, .Period, ".");
const field_ident = try transCreateNodeIdentifier(c, field_name);
node.semicolon_token = try appendToken(c, .Semicolon, ";");
const field_access_node = try c.a().create(ast.Node.InfixOp);
field_access_node.* = .{
.op_token = period_tok,
.lhs = enum_ident,
.op = .Period,
.rhs = field_ident,
};
node.init_node = &field_access_node.base;
try addTopLevelDecl(c, field_name, &node.base);
}
fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
const c_type = qualTypeCanon(qt);
if (ZigClangType_getTypeClass(c_type) != .Builtin)
@ -2591,7 +2579,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
});
},
.FunctionProto => {
.FunctionProto, .FunctionNoProto => {
const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);
return &fn_proto.base;
@ -2666,24 +2654,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
return transCreateNodeIdentifier(rp.c, typedef_name);
return (try transTypeDef(rp.c, typedef_decl)) orelse
revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
},
.Record => {
const record_ty = @ptrCast(*const ZigClangRecordType, ty);
// TODO this sould get the name from decl_table
// struct Foo {
// struct Bar{
// int b;
// };
// struct Bar c;
// };
const record_decl = ZigClangRecordType_getDecl(record_ty);
if (try getContainerName(rp, record_decl)) |name|
return transCreateNodeIdentifier(rp.c, name)
else
return transRecordDecl(rp.c, record_decl);
return (try transRecordDecl(rp.c, record_decl)) orelse
revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
},
.Enum => {
const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
@ -2704,6 +2683,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty);
return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc);
},
.MacroQualified => {
const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty);
return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc);
},
else => {
const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});
@ -2711,22 +2694,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
}
}
fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
const bare_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
"union"
else if (ZigClangRecordDecl_isStruct(record_decl))
"struct"
else
return revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
return null;
return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name });
}
fn isCVoid(qt: ZigClangQualType) bool {
const ty = ZigClangQualType_getTypePtr(qt);
if (ZigClangType_getTypeClass(ty) == .Builtin) {
@ -2909,14 +2876,13 @@ fn finishTransFnProto(
};
const fn_proto = try rp.c.a().create(ast.Node.FnProto);
fn_proto.* = ast.Node.FnProto{
.base = ast.Node{ .id = ast.Node.Id.FnProto },
fn_proto.* = .{
.doc_comments = null,
.visib_token = pub_tok,
.fn_token = fn_tok,
.name_token = name_tok,
.params = fn_params,
.return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },
.return_type = .{ .Explicit = return_type_node },
.var_args_token = null, // TODO this field is broken in the AST data model
.extern_export_inline_token = extern_export_inline_tok,
.cc_token = cc_tok,

View File

@ -228,7 +228,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ struct Foo *foo;
\\};
, &[_][]const u8{
\\pub const struct_Foo = @OpaqueType()
\\pub const struct_Foo = @OpaqueType();
,
\\pub const struct_Bar = extern struct {
\\ foo: ?*struct_Foo,
@ -622,18 +622,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define glClearPFN PFNGLCLEARPROC
, &[_][]const u8{
\\pub const GLbitfield = c_uint;
,
\\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
,
\\pub const OpenGLProc = ?extern fn () void;
,
\\pub const struct_unnamed_1 = extern struct {
\\ Clear: PFNGLCLEARPROC,
\\};
\\pub const union_OpenGLProcs = extern union {
\\ ptr: [1]OpenGLProc,
\\ gl: extern struct {
\\ Clear: PFNGLCLEARPROC,
\\ },
\\ gl: struct_unnamed_1,
\\};
,
\\pub extern var glProcs: union_OpenGLProcs;
,
\\pub const glClearPFN = PFNGLCLEARPROC;
@ -891,6 +888,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add_2("type referenced struct",
\\struct Foo {
\\ struct Bar{
\\ int b;
\\ };
\\ struct Bar c;
\\};
, &[_][]const u8{
\\pub const struct_Bar = extern struct {
\\ b: c_int,
\\};
\\pub const struct_Foo = extern struct {
\\ c: struct_Bar,
\\};
});
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
if (builtin.os != builtin.Os.windows) {