mirror of
https://github.com/ziglang/zig.git
synced 2026-01-03 12:03:19 +00:00
commit
a5cb19c0ac
@ -812,6 +812,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str
|
||||
pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
|
||||
pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool;
|
||||
pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;
|
||||
pub extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(self: ?*const struct_ZigClangType, *const ZigClangASTContext) bool;
|
||||
pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;
|
||||
pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;
|
||||
pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
|
||||
|
||||
@ -793,6 +793,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
|
||||
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);
|
||||
const field_qt = ZigClangFieldDecl_getType(field_decl);
|
||||
|
||||
if (ZigClangFieldDecl_isBitField(field_decl)) {
|
||||
const opaque = try transCreateNodeOpaqueType(c);
|
||||
@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
|
||||
break :blk opaque;
|
||||
}
|
||||
|
||||
if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
|
||||
const opaque = try transCreateNodeOpaqueType(c);
|
||||
semicolon = try appendToken(c, .Semicolon, ";");
|
||||
try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
|
||||
break :blk opaque;
|
||||
}
|
||||
|
||||
var is_anon = false;
|
||||
var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
|
||||
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
|
||||
@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
|
||||
}
|
||||
const field_name = try appendIdentifier(c, raw_name);
|
||||
_ = try appendToken(c, .Colon, ":");
|
||||
const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {
|
||||
const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
const opaque = try transCreateNodeOpaqueType(c);
|
||||
semicolon = try appendToken(c, .Semicolon, ";");
|
||||
@ -2237,6 +2245,7 @@ fn transWhileLoop(
|
||||
.id = .Loop,
|
||||
};
|
||||
while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &while_node.base;
|
||||
}
|
||||
|
||||
@ -2346,8 +2355,10 @@ fn transForLoop(
|
||||
try block_scope.?.block_node.statements.push(&while_node.base);
|
||||
block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
|
||||
return &block_scope.?.block_node.base;
|
||||
} else
|
||||
} else {
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &while_node.base;
|
||||
}
|
||||
}
|
||||
|
||||
fn transSwitch(
|
||||
@ -5431,6 +5442,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
//else
|
||||
// @as(dest, x)
|
||||
|
||||
const lparen = try appendToken(c, .LParen, "(");
|
||||
|
||||
const if_1 = try transCreateNodeIf(c);
|
||||
const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
|
||||
const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
|
||||
@ -5492,7 +5505,13 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
as.rparen_token = try appendToken(c, .RParen, ")");
|
||||
else_2.body = &as.base;
|
||||
|
||||
return &if_1.base;
|
||||
const group_node = try c.a().create(ast.Node.GroupedExpression);
|
||||
group_node.* = .{
|
||||
.lparen = lparen,
|
||||
.expr = &if_1.base,
|
||||
.rparen = try appendToken(c, .RParen, ")"),
|
||||
};
|
||||
return &group_node.base;
|
||||
},
|
||||
else => {
|
||||
const first_tok = it.list.at(0);
|
||||
@ -5545,14 +5564,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
);
|
||||
return error.ParseError;
|
||||
}
|
||||
// deref is often used together with casts so we group the lhs expression
|
||||
const group = try c.a().create(ast.Node.GroupedExpression);
|
||||
group.* = .{
|
||||
.lparen = try appendToken(c, .LParen, "("),
|
||||
.expr = node,
|
||||
.rparen = try appendToken(c, .RParen, ")"),
|
||||
};
|
||||
const deref = try transCreateNodePtrDeref(c, &group.base);
|
||||
const deref = try transCreateNodePtrDeref(c, node);
|
||||
node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]);
|
||||
continue;
|
||||
},
|
||||
@ -5596,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
},
|
||||
.Ampersand => {
|
||||
op_token = try appendToken(c, .Ampersand, "&");
|
||||
op_id .BitAnd;
|
||||
op_id = .BitAnd;
|
||||
},
|
||||
.Plus => {
|
||||
op_token = try appendToken(c, .Plus, "+");
|
||||
@ -5604,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
},
|
||||
.Minus => {
|
||||
op_token = try appendToken(c, .Minus, "-");
|
||||
op_id .Sub;
|
||||
op_id = .Sub;
|
||||
},
|
||||
.AmpersandAmpersand => {
|
||||
op_token = try appendToken(c, .Keyword_and, "and");
|
||||
@ -5676,19 +5688,17 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
},
|
||||
.BangEqual => {
|
||||
op_token = try appendToken(c, .BangEqual, "!=");
|
||||
op_id = .BangEqual;
|
||||
op_id = .BangEqual;
|
||||
},
|
||||
.EqualEqual => {
|
||||
op_token = try appendToken(c, .EqualEqual, "==");
|
||||
op_id = .EqualEqual;
|
||||
},
|
||||
.Slash => {
|
||||
// unsigned/float division uses the operator
|
||||
op_id = .Div;
|
||||
op_token = try appendToken(c, .Slash, "/");
|
||||
},
|
||||
.Percent => {
|
||||
// unsigned/float division uses the operator
|
||||
op_id = .Mod;
|
||||
op_token = try appendToken(c, .Percent, "%");
|
||||
},
|
||||
@ -5729,25 +5739,12 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
|
||||
return &node.base;
|
||||
},
|
||||
.Asterisk => {
|
||||
// deref is often used together with casts so we group the lhs expression
|
||||
const group = try c.a().create(ast.Node.GroupedExpression);
|
||||
group.* = .{
|
||||
.lparen = try appendToken(c, .LParen, "("),
|
||||
.expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
|
||||
.rparen = try appendToken(c, .RParen, ")"),
|
||||
};
|
||||
return try transCreateNodePtrDeref(c, &group.base);
|
||||
const node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||
return try transCreateNodePtrDeref(c, node);
|
||||
},
|
||||
.Ampersand => {
|
||||
// address of is often used together with casts so we group the rhs expression
|
||||
const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
|
||||
const group = try c.a().create(ast.Node.GroupedExpression);
|
||||
group.* = .{
|
||||
.lparen = try appendToken(c, .LParen, "("),
|
||||
.expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
|
||||
.rparen = try appendToken(c, .RParen, ")"),
|
||||
};
|
||||
node.rhs = &group.base;
|
||||
node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
|
||||
return &node.base;
|
||||
},
|
||||
else => {
|
||||
|
||||
@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
|
||||
return casted->isRecordType();
|
||||
}
|
||||
|
||||
bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
|
||||
const struct ZigClangASTContext *ctx)
|
||||
{
|
||||
auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
|
||||
auto casted = reinterpret_cast<const clang::QualType *>(self);
|
||||
auto casted_type = reinterpret_cast<const clang::Type *>(self);
|
||||
if (casted_type->isIncompleteArrayType())
|
||||
return true;
|
||||
|
||||
clang::QualType elem_type = *casted;
|
||||
while (const clang::ConstantArrayType *ArrayT = casted_ctx->getAsConstantArrayType(elem_type)) {
|
||||
if (ArrayT->getSize() == 0)
|
||||
return true;
|
||||
|
||||
elem_type = ArrayT->getElementType();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZigClangType_isConstantArrayType(const ZigClangType *self) {
|
||||
auto casted = reinterpret_cast<const clang::Type *>(self);
|
||||
return casted->isConstantArrayType();
|
||||
|
||||
@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
|
||||
ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
|
||||
ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
|
||||
ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
|
||||
ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
|
||||
ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
|
||||
ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
|
||||
ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self);
|
||||
|
||||
@ -3,6 +3,31 @@ const std = @import("std");
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("structs with VLAs are rejected",
|
||||
\\struct foo { int x; int y[]; };
|
||||
\\struct bar { int x; int y[0]; };
|
||||
, &[_][]const u8{
|
||||
\\pub const struct_foo = @OpaqueType();
|
||||
,
|
||||
\\pub const struct_bar = @OpaqueType();
|
||||
});
|
||||
|
||||
cases.add("nested loops without blocks",
|
||||
\\void foo() {
|
||||
\\ while (0) while (0) {}
|
||||
\\ for (;;) while (0);
|
||||
\\ for (;;) do {} while (0);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ while (@as(c_int, 0) != 0) while (@as(c_int, 0) != 0) {};
|
||||
\\ while (true) while (@as(c_int, 0) != 0) {};
|
||||
\\ while (true) while (true) {
|
||||
\\ if (!(@as(c_int, 0) != 0)) break;
|
||||
\\ };
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("macro comma operator",
|
||||
\\#define foo (foo, bar)
|
||||
\\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
|
||||
@ -14,7 +39,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) {
|
||||
\\ return blk: {
|
||||
\\ _ = &(x);
|
||||
\\ _ = &x;
|
||||
\\ _ = 3;
|
||||
\\ _ = 4 == 4;
|
||||
\\ _ = 5 * 6;
|
||||
@ -1404,7 +1429,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("macro pointer cast",
|
||||
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
|
||||
, &[_][]const u8{
|
||||
\\pub const NRF_GPIO = if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
|
||||
\\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
|
||||
});
|
||||
|
||||
cases.add("basic macro function",
|
||||
@ -1993,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\pub const DOT = a.b;
|
||||
,
|
||||
\\pub const ARROW = (a).*.b;
|
||||
\\pub const ARROW = a.*.b;
|
||||
});
|
||||
|
||||
cases.add("array access",
|
||||
@ -2588,11 +2613,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\#define FOO(bar) baz((void *)(baz))
|
||||
\\#define BAR (void*) a
|
||||
, &[_][]const u8{
|
||||
\\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) {
|
||||
\\ return baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz));
|
||||
\\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
|
||||
\\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
|
||||
\\}
|
||||
,
|
||||
\\pub const BAR = if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a);
|
||||
\\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a));
|
||||
});
|
||||
|
||||
cases.add("macro conditional operator",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user