@@ -3379,6 +3379,49 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
3379
3379
return maybeSuppressResult (c , used , res );
3380
3380
}
3381
3381
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
+
3382
3425
fn transMemberExpr (c : * Context , scope : * Scope , stmt : * const clang.MemberExpr , result_used : ResultUsed ) TransError ! Node {
3383
3426
var container_node = try transExpr (c , scope , stmt .getBase (), .used );
3384
3427
if (stmt .isArrow ()) {
@@ -3405,6 +3448,15 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
3405
3448
if (exprIsFlexibleArrayRef (c , @as (* const clang .Expr , @ptrCast (stmt )))) {
3406
3449
node = try Tag .call .create (c .arena , .{ .lhs = node , .args = &.{} });
3407
3450
}
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
+ }
3408
3460
return maybeSuppressResult (c , result_used , node );
3409
3461
}
3410
3462
@@ -3417,6 +3469,7 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
3417
3469
fn transSignedArrayAccess (
3418
3470
c : * Context ,
3419
3471
scope : * Scope ,
3472
+ stmt : * const clang.ArraySubscriptExpr ,
3420
3473
container_expr : * const clang.Expr ,
3421
3474
subscr_expr : * const clang.Expr ,
3422
3475
result_used : ResultUsed ,
@@ -3481,7 +3534,13 @@ fn transSignedArrayAccess(
3481
3534
try block_scope .statements .append (if_node );
3482
3535
const block_node = try block_scope .complete (c );
3483
3536
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 );
3485
3544
3486
3545
return maybeSuppressResult (c , result_used , derefed );
3487
3546
}
@@ -3511,7 +3570,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
3511
3570
// Special case: actual pointer (not decayed array) and signed integer subscript
3512
3571
// See discussion at https://github.com/ziglang/zig/pull/8589
3513
3572
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 );
3515
3574
3516
3575
const container_node = try transExpr (c , scope , unwrapped_base , .used );
3517
3576
const rhs = if (is_longlong or is_signed ) blk : {
@@ -3526,10 +3585,15 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
3526
3585
});
3527
3586
} else try transExpr (c , scope , subscr_expr , .used );
3528
3587
3529
- const node = try Tag .array_access .create (c .arena , .{
3588
+ var node = try Tag .array_access .create (c .arena , .{
3530
3589
.lhs = container_node ,
3531
3590
.rhs = rhs ,
3532
3591
});
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
+ }
3533
3597
return maybeSuppressResult (c , result_used , node );
3534
3598
}
3535
3599
@@ -3714,17 +3778,29 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
3714
3778
else
3715
3779
return transCreatePreCrement (c , scope , stmt , .sub_assign , used ),
3716
3780
.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
+ }
3718
3789
},
3719
3790
.Deref = > {
3720
3791
if (qualTypeWasDemotedToOpaque (c , stmt .getType ()))
3721
3792
return fail (c , error .UnsupportedTranslation , stmt .getBeginLoc (), "cannot dereference opaque type" , .{});
3722
3793
3723
- const node = try transExpr (c , scope , op_expr , used );
3794
+ var node = try transExpr (c , scope , op_expr , used );
3724
3795
var is_ptr = false ;
3725
3796
const fn_ty = qualTypeGetFnProto (op_expr .getType (), & is_ptr );
3726
3797
if (fn_ty != null and is_ptr )
3727
3798
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
+ }
3728
3804
return Tag .deref .create (c .arena , node );
3729
3805
},
3730
3806
.Plus = > return transExpr (c , scope , op_expr , used ),
0 commit comments