mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
parent
d8b133d733
commit
45212e3b33
@ -1355,3 +1355,34 @@ test "isError" {
|
||||
try std.testing.expect(isError(math.absInt(@as(i8, -128))));
|
||||
try std.testing.expect(!isError(math.absInt(@as(i8, -127))));
|
||||
}
|
||||
|
||||
/// This function is for translate-c and is not intended for general use.
|
||||
/// Constructs a [*c] pointer with the const and volatile annotations
|
||||
/// from SelfType for pointing to a C flexible array of ElementType.
|
||||
pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type {
|
||||
switch (@typeInfo(SelfType)) {
|
||||
.Pointer => |ptr| {
|
||||
return @Type(TypeInfo{ .Pointer = .{
|
||||
.size = .C,
|
||||
.is_const = ptr.is_const,
|
||||
.is_volatile = ptr.is_volatile,
|
||||
.alignment = @alignOf(ElementType),
|
||||
.child = ElementType,
|
||||
.is_allowzero = true,
|
||||
.sentinel = null,
|
||||
} });
|
||||
},
|
||||
else => |info| @compileError("Invalid self type \"" ++ @tagName(info) ++ "\" for flexible array getter: " ++ @typeName(SelfType)),
|
||||
}
|
||||
}
|
||||
|
||||
test "Flexible Array Type" {
|
||||
const Container = extern struct {
|
||||
size: usize,
|
||||
};
|
||||
|
||||
try testing.expectEqual(FlexibleArrayType(*Container, c_int), [*c]c_int);
|
||||
try testing.expectEqual(FlexibleArrayType(*const Container, c_int), [*c]const c_int);
|
||||
try testing.expectEqual(FlexibleArrayType(*volatile Container, c_int), [*c]volatile c_int);
|
||||
try testing.expectEqual(FlexibleArrayType(*const volatile Container, c_int), [*c]const volatile c_int);
|
||||
}
|
||||
|
||||
@ -183,6 +183,14 @@ pub const ArrayType = opaque {
|
||||
extern fn ZigClangArrayType_getElementType(*const ArrayType) QualType;
|
||||
};
|
||||
|
||||
pub const ASTRecordLayout = opaque {
|
||||
pub const getFieldOffset = ZigClangASTRecordLayout_getFieldOffset;
|
||||
extern fn ZigClangASTRecordLayout_getFieldOffset(*const ASTRecordLayout, c_uint) u64;
|
||||
|
||||
pub const getAlignment = ZigClangASTRecordLayout_getAlignment;
|
||||
extern fn ZigClangASTRecordLayout_getAlignment(*const ASTRecordLayout) i64;
|
||||
};
|
||||
|
||||
pub const AttributedType = opaque {
|
||||
pub const getEquivalentType = ZigClangAttributedType_getEquivalentType;
|
||||
extern fn ZigClangAttributedType_getEquivalentType(*const AttributedType) QualType;
|
||||
@ -461,6 +469,9 @@ pub const FieldDecl = opaque {
|
||||
|
||||
pub const getParent = ZigClangFieldDecl_getParent;
|
||||
extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl;
|
||||
|
||||
pub const getFieldIndex = ZigClangFieldDecl_getFieldIndex;
|
||||
extern fn ZigClangFieldDecl_getFieldIndex(*const FieldDecl) c_uint;
|
||||
};
|
||||
|
||||
pub const FileID = opaque {};
|
||||
@ -752,6 +763,9 @@ pub const RecordDecl = opaque {
|
||||
pub const getLocation = ZigClangRecordDecl_getLocation;
|
||||
extern fn ZigClangRecordDecl_getLocation(*const RecordDecl) SourceLocation;
|
||||
|
||||
pub const getASTRecordLayout = ZigClangRecordDecl_getASTRecordLayout;
|
||||
extern fn ZigClangRecordDecl_getASTRecordLayout(*const RecordDecl, *const ASTContext) *const ASTRecordLayout;
|
||||
|
||||
pub const field_begin = ZigClangRecordDecl_field_begin;
|
||||
extern fn ZigClangRecordDecl_field_begin(*const RecordDecl) field_iterator;
|
||||
|
||||
|
||||
@ -819,6 +819,111 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNa
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a getter function for a flexible array member at the end of a C struct
|
||||
/// e.g. `T items[]` or `T items[0]`. The generated function returns a [*c] pointer
|
||||
/// to the flexible array with the correct const and volatile qualifiers
|
||||
fn buildFlexibleArrayFn(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
layout: *const clang.ASTRecordLayout,
|
||||
field_name: []const u8,
|
||||
field_decl: *const clang.FieldDecl,
|
||||
) TypeError!Node {
|
||||
const field_qt = field_decl.getType();
|
||||
|
||||
const u8_type = try Tag.type.create(c.arena, "u8");
|
||||
const self_param_name = "self";
|
||||
const self_param = try Tag.identifier.create(c.arena, self_param_name);
|
||||
const self_type = try Tag.typeof.create(c.arena, self_param);
|
||||
|
||||
const fn_params = try c.arena.alloc(ast.Payload.Param, 1);
|
||||
|
||||
fn_params[0] = .{
|
||||
.name = self_param_name,
|
||||
.type = Tag.@"anytype".init(),
|
||||
.is_noalias = false,
|
||||
};
|
||||
|
||||
const array_type = @ptrCast(*const clang.ArrayType, field_qt.getTypePtr());
|
||||
const element_qt = array_type.getElementType();
|
||||
const element_type = try transQualType(c, scope, element_qt, field_decl.getLocation());
|
||||
|
||||
var block_scope = try Scope.Block.init(c, scope, false);
|
||||
defer block_scope.deinit();
|
||||
|
||||
const intermediate_type_name = try block_scope.makeMangledName(c, "Intermediate");
|
||||
const intermediate_type = try Tag.std_meta_flexible_array_type.create(c.arena, .{ .lhs = self_type, .rhs = u8_type });
|
||||
const intermediate_type_decl = try Tag.var_simple.create(c.arena, .{
|
||||
.name = intermediate_type_name,
|
||||
.init = intermediate_type,
|
||||
});
|
||||
try block_scope.statements.append(intermediate_type_decl);
|
||||
const intermediate_type_ident = try Tag.identifier.create(c.arena, intermediate_type_name);
|
||||
|
||||
const return_type_name = try block_scope.makeMangledName(c, "ReturnType");
|
||||
const return_type = try Tag.std_meta_flexible_array_type.create(c.arena, .{ .lhs = self_type, .rhs = element_type });
|
||||
const return_type_decl = try Tag.var_simple.create(c.arena, .{
|
||||
.name = return_type_name,
|
||||
.init = return_type,
|
||||
});
|
||||
try block_scope.statements.append(return_type_decl);
|
||||
const return_type_ident = try Tag.identifier.create(c.arena, return_type_name);
|
||||
|
||||
const field_index = field_decl.getFieldIndex();
|
||||
const bit_offset = layout.getFieldOffset(field_index); // this is a target-specific constant based on the struct layout
|
||||
const byte_offset = bit_offset / 8;
|
||||
|
||||
const casted_self = try Tag.ptr_cast.create(c.arena, .{
|
||||
.lhs = intermediate_type_ident,
|
||||
.rhs = self_param,
|
||||
});
|
||||
const field_offset = try transCreateNodeNumber(c, byte_offset, .int);
|
||||
const field_ptr = try Tag.add.create(c.arena, .{ .lhs = casted_self, .rhs = field_offset });
|
||||
|
||||
const alignment = try Tag.alignof.create(c.arena, element_type);
|
||||
|
||||
const ptr_val = try Tag.align_cast.create(c.arena, .{ .lhs = alignment, .rhs = field_ptr });
|
||||
const ptr_cast = try Tag.ptr_cast.create(c.arena, .{ .lhs = return_type_ident, .rhs = ptr_val });
|
||||
const return_stmt = try Tag.@"return".create(c.arena, ptr_cast);
|
||||
try block_scope.statements.append(return_stmt);
|
||||
|
||||
const payload = try c.arena.create(ast.Payload.Func);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .func },
|
||||
.data = .{
|
||||
.is_pub = true,
|
||||
.is_extern = false,
|
||||
.is_export = false,
|
||||
.is_var_args = false,
|
||||
.name = field_name,
|
||||
.linksection_string = null,
|
||||
.explicit_callconv = null,
|
||||
.params = fn_params,
|
||||
.return_type = return_type,
|
||||
.body = try block_scope.complete(c),
|
||||
.alignment = null,
|
||||
},
|
||||
};
|
||||
return Node.initPayload(&payload.base);
|
||||
}
|
||||
|
||||
fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool {
|
||||
return qualTypeCanon(field_decl.getType()).isIncompleteOrZeroLengthArrayType(c.clang_context);
|
||||
}
|
||||
|
||||
/// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining
|
||||
/// this because it returns false for a record that ends with a zero-length
|
||||
/// array, but we consider those to be flexible arrays
|
||||
fn hasFlexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) bool {
|
||||
var it = record_def.field_begin();
|
||||
const end_it = record_def.field_end();
|
||||
while (it.neq(end_it)) : (it = it.next()) {
|
||||
const field_decl = it.deref();
|
||||
if (isFlexibleArrayFieldDecl(c, field_decl)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {
|
||||
if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|
|
||||
return; // Avoid processing this decl twice
|
||||
@ -868,9 +973,16 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa);
|
||||
defer fields.deinit();
|
||||
|
||||
var functions = std.ArrayList(Node).init(c.gpa);
|
||||
defer functions.deinit();
|
||||
|
||||
const has_flexible_array = hasFlexibleArrayField(c, record_def);
|
||||
var unnamed_field_count: u32 = 0;
|
||||
var it = record_def.field_begin();
|
||||
const end_it = record_def.field_end();
|
||||
const layout = record_def.getASTRecordLayout(c.clang_context);
|
||||
const record_alignment = layout.getAlignment();
|
||||
|
||||
while (it.neq(end_it)) : (it = it.next()) {
|
||||
const field_decl = it.deref();
|
||||
const field_loc = field_decl.getLocation();
|
||||
@ -882,12 +994,6 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
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, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
}
|
||||
|
||||
var is_anon = false;
|
||||
var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
|
||||
if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
|
||||
@ -896,6 +1002,18 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
unnamed_field_count += 1;
|
||||
is_anon = true;
|
||||
}
|
||||
if (isFlexibleArrayFieldDecl(c, field_decl)) {
|
||||
const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of flexible array field {s}", .{ container_kind_name, field_name });
|
||||
break :blk Tag.opaque_literal.init();
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try functions.append(flexible_array_fn);
|
||||
continue;
|
||||
}
|
||||
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()), {});
|
||||
@ -905,7 +1023,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
const alignment = zigAlignment(field_decl.getAlignedAttribute(c.clang_context));
|
||||
const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)
|
||||
@intCast(c_uint, record_alignment)
|
||||
else
|
||||
zigAlignment(field_decl.getAlignedAttribute(c.clang_context));
|
||||
|
||||
if (is_anon) {
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
|
||||
@ -924,6 +1045,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
.data = .{
|
||||
.is_packed = is_packed,
|
||||
.fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items),
|
||||
.functions = try c.arena.dupe(Node, functions.items),
|
||||
},
|
||||
};
|
||||
break :blk Node.initPayload(&record_payload.base);
|
||||
@ -1737,12 +1859,12 @@ fn transImplicitCastExpr(
|
||||
return maybeSuppressResult(c, scope, result_used, sub_expr_node);
|
||||
},
|
||||
.ArrayToPointerDecay => {
|
||||
if (exprIsNarrowStringLiteral(sub_expr)) {
|
||||
const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
|
||||
const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
|
||||
if (exprIsNarrowStringLiteral(sub_expr) or exprIsFlexibleArrayRef(c, sub_expr)) {
|
||||
return maybeSuppressResult(c, scope, result_used, sub_expr_node);
|
||||
}
|
||||
|
||||
const addr = try Tag.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used));
|
||||
const addr = try Tag.address_of.create(c.arena, sub_expr_node);
|
||||
const casted = try transCPtrCast(c, scope, expr.getBeginLoc(), dest_type, src_type, addr);
|
||||
return maybeSuppressResult(c, scope, result_used, casted);
|
||||
},
|
||||
@ -1852,6 +1974,19 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn exprIsFlexibleArrayRef(c: *Context, expr: *const clang.Expr) bool {
|
||||
if (expr.getStmtClass() == .MemberExprClass) {
|
||||
const member_expr = @ptrCast(*const clang.MemberExpr, expr);
|
||||
const member_decl = member_expr.getMemberDecl();
|
||||
const decl_kind = @ptrCast(*const clang.Decl, member_decl).getKind();
|
||||
if (decl_kind == .Field) {
|
||||
const field_decl = @ptrCast(*const clang.FieldDecl, member_decl);
|
||||
return isFlexibleArrayFieldDecl(c, field_decl);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn isBoolRes(res: Node) bool {
|
||||
switch (res.tag()) {
|
||||
.@"or",
|
||||
@ -3056,7 +3191,6 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
|
||||
|
||||
fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
|
||||
var container_node = try transExpr(c, scope, stmt.getBase(), .used);
|
||||
|
||||
if (stmt.isArrow()) {
|
||||
container_node = try Tag.deref.create(c.arena, container_node);
|
||||
}
|
||||
@ -3076,7 +3210,11 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
|
||||
const decl = @ptrCast(*const clang.NamedDecl, member_decl);
|
||||
break :blk try c.str(decl.getName_bytes_begin());
|
||||
};
|
||||
const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .field_name = name });
|
||||
|
||||
var node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .field_name = name });
|
||||
if (exprIsFlexibleArrayRef(c, @ptrCast(*const clang.Expr, stmt))) {
|
||||
node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &.{} });
|
||||
}
|
||||
return maybeSuppressResult(c, scope, result_used, node);
|
||||
}
|
||||
|
||||
|
||||
@ -193,6 +193,8 @@ pub const Node = extern union {
|
||||
|
||||
/// @import("std").meta.sizeof(operand)
|
||||
std_meta_sizeof,
|
||||
/// @import("std").meta.FlexibleArrayType(lhs, rhs)
|
||||
std_meta_flexible_array_type,
|
||||
/// @import("std").meta.shuffleVectorIndex(lhs, rhs)
|
||||
std_meta_shuffle_vector_index,
|
||||
/// @import("std").meta.Vector(lhs, rhs)
|
||||
@ -328,6 +330,7 @@ pub const Node = extern union {
|
||||
.align_cast,
|
||||
.array_access,
|
||||
.std_mem_zeroinit,
|
||||
.std_meta_flexible_array_type,
|
||||
.std_meta_shuffle_vector_index,
|
||||
.std_meta_vector,
|
||||
.ptr_cast,
|
||||
@ -567,6 +570,7 @@ pub const Payload = struct {
|
||||
data: struct {
|
||||
is_packed: bool,
|
||||
fields: []Field,
|
||||
functions: []Node,
|
||||
},
|
||||
|
||||
pub const Field = struct {
|
||||
@ -909,6 +913,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
const import_node = try renderStdImport(c, "mem", "zeroInit");
|
||||
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.std_meta_flexible_array_type => {
|
||||
const payload = node.castTag(.std_meta_flexible_array_type).?.data;
|
||||
const import_node = try renderStdImport(c, "meta", "FlexibleArrayType");
|
||||
return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.std_meta_shuffle_vector_index => {
|
||||
const payload = node.castTag(.std_meta_shuffle_vector_index).?.data;
|
||||
const import_node = try renderStdImport(c, "meta", "shuffleVectorIndex");
|
||||
@ -1992,7 +2001,10 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
|
||||
try c.addToken(.keyword_union, "union");
|
||||
|
||||
_ = try c.addToken(.l_brace, "{");
|
||||
const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.fields.len, 2));
|
||||
|
||||
const num_funcs = payload.functions.len;
|
||||
const total_members = payload.fields.len + num_funcs;
|
||||
const members = try c.gpa.alloc(NodeIndex, std.math.max(total_members, 2));
|
||||
defer c.gpa.free(members);
|
||||
members[0] = 0;
|
||||
members[1] = 0;
|
||||
@ -2033,9 +2045,12 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
|
||||
});
|
||||
_ = try c.addToken(.comma, ",");
|
||||
}
|
||||
for (payload.functions) |function, i| {
|
||||
members[payload.fields.len + i] = try renderNode(c, function);
|
||||
}
|
||||
_ = try c.addToken(.r_brace, "}");
|
||||
|
||||
if (payload.fields.len == 0) {
|
||||
if (total_members == 0) {
|
||||
return c.addNode(.{
|
||||
.tag = .container_decl_two,
|
||||
.main_token = kind_tok,
|
||||
@ -2044,9 +2059,9 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
|
||||
.rhs = 0,
|
||||
},
|
||||
});
|
||||
} else if (payload.fields.len <= 2) {
|
||||
} else if (total_members <= 2) {
|
||||
return c.addNode(.{
|
||||
.tag = .container_decl_two_trailing,
|
||||
.tag = if (num_funcs == 0) .container_decl_two_trailing else .container_decl_two,
|
||||
.main_token = kind_tok,
|
||||
.data = .{
|
||||
.lhs = members[0],
|
||||
@ -2056,7 +2071,7 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
|
||||
} else {
|
||||
const span = try c.listToSpan(members);
|
||||
return c.addNode(.{
|
||||
.tag = .container_decl_trailing,
|
||||
.tag = if (num_funcs == 0) .container_decl_trailing else .container_decl,
|
||||
.main_token = kind_tok,
|
||||
.data = .{
|
||||
.lhs = span.start,
|
||||
@ -2229,6 +2244,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.std_meta_promoteIntLiteral,
|
||||
.std_meta_vector,
|
||||
.std_meta_shuffle_vector_index,
|
||||
.std_meta_flexible_array_type,
|
||||
.std_mem_zeroinit,
|
||||
.integer_literal,
|
||||
.float_literal,
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include <clang/AST/APValue.h>
|
||||
#include <clang/AST/Attr.h>
|
||||
#include <clang/AST/Expr.h>
|
||||
#include <clang/AST/RecordLayout.h>
|
||||
|
||||
#if __GNUC__ >= 8
|
||||
#pragma GCC diagnostic pop
|
||||
@ -2716,6 +2717,22 @@ struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct ZigClangCSty
|
||||
return bitcast(casted->getType());
|
||||
}
|
||||
|
||||
const struct ZigClangASTRecordLayout *ZigClangRecordDecl_getASTRecordLayout(const struct ZigClangRecordDecl *self, const struct ZigClangASTContext *ctx) {
|
||||
auto casted_self = reinterpret_cast<const clang::RecordDecl *>(self);
|
||||
auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
|
||||
const clang::ASTRecordLayout &layout = casted_ctx->getASTRecordLayout(casted_self);
|
||||
return reinterpret_cast<const struct ZigClangASTRecordLayout *>(&layout);
|
||||
}
|
||||
|
||||
uint64_t ZigClangASTRecordLayout_getFieldOffset(const struct ZigClangASTRecordLayout *self, unsigned field_no) {
|
||||
return reinterpret_cast<const clang::ASTRecordLayout *>(self)->getFieldOffset(field_no);
|
||||
}
|
||||
|
||||
int64_t ZigClangASTRecordLayout_getAlignment(const struct ZigClangASTRecordLayout *self) {
|
||||
auto casted_self = reinterpret_cast<const clang::ASTRecordLayout *>(self);
|
||||
return casted_self->getAlignment().getQuantity();
|
||||
}
|
||||
|
||||
bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *self, struct ZigClangExprEvalResult *result, const struct ZigClangASTContext *ctx) {
|
||||
auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self);
|
||||
auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
|
||||
@ -3136,6 +3153,11 @@ const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigCla
|
||||
return reinterpret_cast<const ZigClangRecordDecl *>(casted->getParent());
|
||||
}
|
||||
|
||||
unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return casted->getFieldIndex();
|
||||
}
|
||||
|
||||
ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return bitcast(casted->getType());
|
||||
|
||||
@ -91,6 +91,7 @@ struct ZigClangAPFloat;
|
||||
struct ZigClangAPInt;
|
||||
struct ZigClangAPSInt;
|
||||
struct ZigClangASTContext;
|
||||
struct ZigClangASTRecordLayout;
|
||||
struct ZigClangASTUnit;
|
||||
struct ZigClangArraySubscriptExpr;
|
||||
struct ZigClangArrayType;
|
||||
@ -1017,6 +1018,11 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangEnumDecl_getLocation(const st
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangTypedefNameDecl_getLocation(const struct ZigClangTypedefNameDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDecl_getLocation(const struct ZigClangDecl *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangASTRecordLayout *ZigClangRecordDecl_getASTRecordLayout(const struct ZigClangRecordDecl *, const struct ZigClangASTContext *);
|
||||
|
||||
ZIG_EXTERN_C uint64_t ZigClangASTRecordLayout_getFieldOffset(const struct ZigClangASTRecordLayout *, unsigned);
|
||||
ZIG_EXTERN_C int64_t ZigClangASTRecordLayout_getAlignment(const struct ZigClangASTRecordLayout *);
|
||||
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionDecl_getType(const struct ZigClangFunctionDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFunctionDecl_getLocation(const struct ZigClangFunctionDecl *);
|
||||
ZIG_EXTERN_C bool ZigClangFunctionDecl_hasBody(const struct ZigClangFunctionDecl *);
|
||||
@ -1317,6 +1323,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangField
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
|
||||
|
||||
@ -1519,4 +1519,25 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("Flexible arrays",
|
||||
\\#include <stdlib.h>
|
||||
\\#include <stdint.h>
|
||||
\\typedef struct { char foo; int bar; } ITEM;
|
||||
\\typedef struct { size_t count; ITEM items[]; } ITEM_LIST;
|
||||
\\typedef struct { unsigned char count; int items[]; } INT_LIST;
|
||||
\\#define SIZE 10
|
||||
\\int main(void) {
|
||||
\\ ITEM_LIST *list = malloc(sizeof(ITEM_LIST) + SIZE * sizeof(ITEM));
|
||||
\\ for (int i = 0; i < SIZE; i++) list->items[i] = (ITEM) {.foo = i, .bar = i + 1};
|
||||
\\ const ITEM_LIST *const c_list = list;
|
||||
\\ for (int i = 0; i < SIZE; i++) if (c_list->items[i].foo != i || c_list->items[i].bar != i + 1) abort();
|
||||
\\ INT_LIST *int_list = malloc(sizeof(INT_LIST) + SIZE * sizeof(int));
|
||||
\\ for (int i = 0; i < SIZE; i++) int_list->items[i] = i;
|
||||
\\ const INT_LIST *const c_int_list = int_list;
|
||||
\\ const int *const ints = int_list->items;
|
||||
\\ for (int i = 0; i < SIZE; i++) if (ints[i] != i) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
@ -421,13 +421,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\};
|
||||
});
|
||||
|
||||
cases.add("structs with VLAs are rejected",
|
||||
cases.add("struct with flexible array",
|
||||
\\struct foo { int x; int y[]; };
|
||||
\\struct bar { int x; int y[0]; };
|
||||
, &[_][]const u8{
|
||||
\\pub const struct_foo = opaque {};
|
||||
,
|
||||
\\pub const struct_bar = opaque {};
|
||||
\\pub const struct_foo = extern struct {
|
||||
\\ x: c_int align(4),
|
||||
\\ pub fn y(self: anytype) @import("std").meta.FlexibleArrayType(@TypeOf(self), c_int) {
|
||||
\\ const Intermediate = @import("std").meta.FlexibleArrayType(@TypeOf(self), u8);
|
||||
\\ const ReturnType = @import("std").meta.FlexibleArrayType(@TypeOf(self), c_int);
|
||||
\\ return @ptrCast(ReturnType, @alignCast(@alignOf(c_int), @ptrCast(Intermediate, self) + 4));
|
||||
\\ }
|
||||
\\};
|
||||
\\pub const struct_bar = extern struct {
|
||||
\\ x: c_int align(4),
|
||||
\\ pub fn y(self: anytype) @import("std").meta.FlexibleArrayType(@TypeOf(self), c_int) {
|
||||
\\ const Intermediate = @import("std").meta.FlexibleArrayType(@TypeOf(self), u8);
|
||||
\\ const ReturnType = @import("std").meta.FlexibleArrayType(@TypeOf(self), c_int);
|
||||
\\ return @ptrCast(ReturnType, @alignCast(@alignOf(c_int), @ptrCast(Intermediate, self) + 4));
|
||||
\\ }
|
||||
\\};
|
||||
});
|
||||
|
||||
cases.add("nested loops without blocks",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user