Skip to content

Commit c9d6470

Browse files
committed
translate-c: correctly translate pointers to qualified values
1 parent 9c9d393 commit c9d6470

File tree

2 files changed

+176
-5
lines changed

2 files changed

+176
-5
lines changed

src/translate_c.zig

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3379,6 +3379,49 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
33793379
return maybeSuppressResult(c, used, res);
33803380
}
33813381

3382+
fn restoreValueQualifiersPtr(
3383+
c: *Context,
3384+
scope: *Scope,
3385+
expr: *const clang.Expr,
3386+
pointee_ty: clang.QualType,
3387+
address_of_node: Node,
3388+
) TransError!Node {
3389+
const pointer_ty = try Tag.c_pointer.create(c.arena, .{
3390+
.is_const = pointee_ty.isConstQualified(),
3391+
.is_volatile = pointee_ty.isVolatileQualified(),
3392+
.elem_type = try transQualType(c, scope, pointee_ty, expr.getBeginLoc()),
3393+
});
3394+
return try Tag.as.create(c.arena, .{
3395+
.lhs = pointer_ty,
3396+
.rhs = try Tag.ptr_cast.create(c.arena, address_of_node),
3397+
});
3398+
}
3399+
3400+
fn restoreValueQualifiersValue(
3401+
c: *Context,
3402+
scope: *Scope,
3403+
expr: *const clang.Expr,
3404+
expr_ty: clang.QualType,
3405+
node: Node,
3406+
) TransError!Node {
3407+
assert(expr_ty.isVolatileQualified() or expr_ty.isConstQualified());
3408+
// TODO(theofabilous): is this 100% guaranteed?
3409+
// If the result type is an array, don't apply qualifiers (yet). In C, an array cannot be legally
3410+
// used by-value, and anything that looks like a by-value obtention of a whole array isn't *actually*
3411+
// a load -- we don't want to falsely annotate this as a volatile load which cannot be optimized away.
3412+
// Presumably, this expression will later be dereferenced or decay to a pointer, at which point
3413+
// pointer qualifiers will be applied.
3414+
switch (expr_ty.getTypeClass()) {
3415+
// TODO(theofabilous): are there other type classes we will want to ignore?
3416+
// what is a 'ConstantMatrix'? and why is this undocumented?
3417+
.ConstantArray => return node,
3418+
else => {},
3419+
}
3420+
const address_of_node = try Tag.address_of.create(c.arena, node);
3421+
const qual_ptr = try restoreValueQualifiersPtr(c, scope, expr, expr_ty, address_of_node);
3422+
return Tag.deref.create(c.arena, qual_ptr);
3423+
}
3424+
33823425
fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
33833426
var container_node = try transExpr(c, scope, stmt.getBase(), .used);
33843427
if (stmt.isArrow()) {
@@ -3405,6 +3448,15 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
34053448
if (exprIsFlexibleArrayRef(c, @as(*const clang.Expr, @ptrCast(stmt)))) {
34063449
node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &.{} });
34073450
}
3451+
3452+
if (stmt.isArrow()) {
3453+
// TODO(theofabilous): function types, flexible array, opaque demotion?
3454+
const expr = @as(*const clang.Expr, @ptrCast(stmt));
3455+
const expr_ty = expr.getType();
3456+
if (expr_ty.isConstQualified() or expr_ty.isVolatileQualified()) {
3457+
node = try restoreValueQualifiersValue(c, scope, expr, expr_ty, node);
3458+
}
3459+
}
34083460
return maybeSuppressResult(c, result_used, node);
34093461
}
34103462

@@ -3417,6 +3469,7 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
34173469
fn transSignedArrayAccess(
34183470
c: *Context,
34193471
scope: *Scope,
3472+
stmt: *const clang.ArraySubscriptExpr,
34203473
container_expr: *const clang.Expr,
34213474
subscr_expr: *const clang.Expr,
34223475
result_used: ResultUsed,
@@ -3481,7 +3534,13 @@ fn transSignedArrayAccess(
34813534
try block_scope.statements.append(if_node);
34823535
const block_node = try block_scope.complete(c);
34833536

3484-
const derefed = try Tag.deref.create(c.arena, block_node);
3537+
var node = block_node;
3538+
const expr = @as(*const clang.Expr, @ptrCast(stmt));
3539+
const expr_ty = expr.getType();
3540+
if (expr_ty.isConstQualified() or expr_ty.isVolatileQualified()) {
3541+
node = try restoreValueQualifiersPtr(c, scope, expr, expr_ty, node);
3542+
}
3543+
const derefed = try Tag.deref.create(c.arena, node);
34853544

34863545
return maybeSuppressResult(c, result_used, derefed);
34873546
}
@@ -3511,7 +3570,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
35113570
// Special case: actual pointer (not decayed array) and signed integer subscript
35123571
// See discussion at https://github.com/ziglang/zig/pull/8589
35133572
if (is_signed and (base_stmt == unwrapped_base) and !is_vector and !is_nonnegative_int_literal)
3514-
return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used);
3573+
return transSignedArrayAccess(c, scope, stmt, base_stmt, subscr_expr, result_used);
35153574

35163575
const container_node = try transExpr(c, scope, unwrapped_base, .used);
35173576
const rhs = if (is_longlong or is_signed) blk: {
@@ -3526,10 +3585,15 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
35263585
});
35273586
} else try transExpr(c, scope, subscr_expr, .used);
35283587

3529-
const node = try Tag.array_access.create(c.arena, .{
3588+
var node = try Tag.array_access.create(c.arena, .{
35303589
.lhs = container_node,
35313590
.rhs = rhs,
35323591
});
3592+
const expr = @as(*const clang.Expr, @ptrCast(stmt));
3593+
const expr_ty = expr.getType();
3594+
if (expr_ty.isConstQualified() or expr_ty.isVolatileQualified()) {
3595+
node = try restoreValueQualifiersValue(c, scope, expr, expr_ty, node);
3596+
}
35333597
return maybeSuppressResult(c, result_used, node);
35343598
}
35353599

@@ -3714,17 +3778,29 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
37143778
else
37153779
return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
37163780
.AddrOf => {
3717-
return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
3781+
const node = try Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
3782+
const op_ty = op_expr.getType();
3783+
if (op_ty.isVolatileQualified() or op_ty.isConstQualified()) {
3784+
const expr = @as(*const clang.Expr, @ptrCast(stmt));
3785+
return restoreValueQualifiersPtr(c, scope, expr, op_ty, node);
3786+
} else {
3787+
return node;
3788+
}
37183789
},
37193790
.Deref => {
37203791
if (qualTypeWasDemotedToOpaque(c, stmt.getType()))
37213792
return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "cannot dereference opaque type", .{});
37223793

3723-
const node = try transExpr(c, scope, op_expr, used);
3794+
var node = try transExpr(c, scope, op_expr, used);
37243795
var is_ptr = false;
37253796
const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);
37263797
if (fn_ty != null and is_ptr)
37273798
return node;
3799+
const expr = @as(*const clang.Expr, @ptrCast(stmt));
3800+
const expr_ty = expr.getType();
3801+
if (expr_ty.isVolatileQualified() or expr_ty.isConstQualified()) {
3802+
node = try restoreValueQualifiersPtr(c, scope, expr, expr_ty, node);
3803+
}
37283804
return Tag.deref.create(c.arena, node);
37293805
},
37303806
.Plus => return transExpr(c, scope, op_expr, used),
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
typedef volatile int mmio_int;
2+
3+
typedef mmio_int *mmio_int_ptr;
4+
5+
typedef struct {
6+
mmio_int reg;
7+
mmio_int regs[4];
8+
mmio_int regm[2][2];
9+
mmio_int_ptr ptr;
10+
} hw_t;
11+
12+
extern hw_t *hw;
13+
extern hw_t hw_arr[4];
14+
15+
extern const mmio_int reg;
16+
extern mmio_int *regs;
17+
18+
static int hw_reg(void) {
19+
return hw->reg;
20+
}
21+
22+
static typeof(&hw->reg) hw_reg_ptr(void) {
23+
return &hw->reg;
24+
}
25+
26+
static mmio_int_ptr hw_ptr(void) {
27+
return hw->ptr;
28+
}
29+
30+
static typeof(&reg) reg_ptr(void) {
31+
return ®
32+
}
33+
34+
static int hw_regs_0(void) {
35+
return hw->regs[0u];
36+
}
37+
38+
static int hw_0_regs_0(void) {
39+
return hw_arr[0u].regs[0u];
40+
}
41+
42+
static int hw_regm_00(void) {
43+
return hw->regm[0u][0u];
44+
}
45+
46+
static int hw_regm_0_deref(void) {
47+
return *(hw->regm[0u]);
48+
}
49+
50+
static int ptr_arith(void) {
51+
return *(regs+1u);
52+
}
53+
54+
// translate-c
55+
// c_frontend=clang
56+
//
57+
// pub const mmio_int = c_int;
58+
// pub const mmio_int_ptr = [*c]volatile mmio_int;
59+
// pub const hw_t = extern struct {
60+
// reg: mmio_int = @import("std").mem.zeroes(mmio_int),
61+
// regs: [4]mmio_int = @import("std").mem.zeroes([4]mmio_int),
62+
// regm: [2][2]mmio_int = @import("std").mem.zeroes([2][2]mmio_int),
63+
// ptr: mmio_int_ptr = @import("std").mem.zeroes(mmio_int_ptr),
64+
// };
65+
// pub extern var hw: [*c]hw_t;
66+
// pub extern var hw_arr: [4]hw_t;
67+
// pub extern const reg: mmio_int;
68+
// pub extern var regs: [*c]volatile mmio_int;
69+
// pub fn hw_reg() callconv(.c) c_int {
70+
// return @as([*c]volatile mmio_int, @ptrCast(&hw.*.reg)).*;
71+
// }
72+
// pub fn hw_reg_ptr() callconv(.c) @TypeOf(@as([*c]volatile mmio_int, @ptrCast(&@as([*c]volatile mmio_int, @ptrCast(&hw.*.reg)).*))) {
73+
// return @as([*c]volatile mmio_int, @ptrCast(&@as([*c]volatile mmio_int, @ptrCast(&hw.*.reg)).*));
74+
// }
75+
// pub fn hw_ptr() callconv(.c) mmio_int_ptr {
76+
// return hw.*.ptr;
77+
// }
78+
// pub fn reg_ptr() callconv(.c) @TypeOf(@as([*c]const volatile mmio_int, @ptrCast(&reg))) {
79+
// return @as([*c]const volatile mmio_int, @ptrCast(&reg));
80+
// }
81+
// pub fn hw_regs_0() callconv(.c) c_int {
82+
// return @as([*c]volatile mmio_int, @ptrCast(&hw.*.regs[@as(c_uint, 0)])).*;
83+
// }
84+
// pub fn hw_0_regs_0() callconv(.c) c_int {
85+
// return @as([*c]volatile mmio_int, @ptrCast(&hw_arr[@as(c_uint, 0)].regs[@as(c_uint, 0)])).*;
86+
// }
87+
// pub fn hw_regm_00() callconv(.c) c_int {
88+
// return @as([*c]volatile mmio_int, @ptrCast(&hw.*.regm[@as(c_uint, 0)][@as(c_uint, 0)])).*;
89+
// }
90+
// pub fn hw_regm_0_deref() callconv(.c) c_int {
91+
// return @as([*c]volatile mmio_int, @ptrCast(@as([*c]volatile mmio_int, @ptrCast(@alignCast(&hw.*.regm[@as(c_uint, 0)]))))).*;
92+
// }
93+
// pub fn ptr_arith() callconv(.c) c_int {
94+
// return @as([*c]volatile mmio_int, @ptrCast(regs + @as(c_uint, 1))).*;
95+
// }

0 commit comments

Comments
 (0)