| ... | @@ -3273,30 +3273,113 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re | ... | @@ -3273,30 +3273,113 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re |
| 3273 | return maybeSuppressResult(c, scope, result_used, node); | 3273 | return maybeSuppressResult(c, scope, result_used, node); |
| 3274 | } | 3274 | } |
| 3275 | | 3275 | |
| | 3276 | /// ptr[subscr] (`subscr` is a signed integer expression, `ptr` a pointer) becomes: |
| | 3277 | /// (blk: { |
| | 3278 | /// const tmp = subscr; |
| | 3279 | /// if (tmp >= 0) break :blk ptr + @intCast(usize, tmp) else break :blk ptr - ~@bitCast(usize, @intCast(isize, tmp) +% -1); |
| | 3280 | /// }).* |
| | 3281 | /// Todo: rip this out once `[*]T + isize` becomes valid. |
| | 3282 | fn transSignedArrayAccess( |
| | 3283 | c: *Context, |
| | 3284 | scope: *Scope, |
| | 3285 | container_expr: *const clang.Expr, |
| | 3286 | subscr_expr: *const clang.Expr, |
| | 3287 | result_used: ResultUsed, |
| | 3288 | ) TransError!Node { |
| | 3289 | var block_scope = try Scope.Block.init(c, scope, true); |
| | 3290 | defer block_scope.deinit(); |
| | 3291 | |
| | 3292 | const tmp = try block_scope.makeMangledName(c, "tmp"); |
| | 3293 | |
| | 3294 | const subscr_node = try transExpr(c, &block_scope.base, subscr_expr, .used); |
| | 3295 | const subscr_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = subscr_node }); |
| | 3296 | try block_scope.statements.append(subscr_decl); |
| | 3297 | |
| | 3298 | const tmp_ref = try Tag.identifier.create(c.arena, tmp); |
| | 3299 | |
| | 3300 | const container_node = try transExpr(c, &block_scope.base, container_expr, .used); |
| | 3301 | |
| | 3302 | const cond_node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = tmp_ref, .rhs = Tag.zero_literal.init() }); |
| | 3303 | |
| | 3304 | const then_value = try Tag.add.create(c.arena, .{ |
| | 3305 | .lhs = container_node, |
| | 3306 | .rhs = try Tag.int_cast.create(c.arena, .{ |
| | 3307 | .lhs = try Tag.identifier.create(c.arena, "usize"), |
| | 3308 | .rhs = tmp_ref, |
| | 3309 | }), |
| | 3310 | }); |
| | 3311 | |
| | 3312 | const then_body = try Tag.break_val.create(c.arena, .{ |
| | 3313 | .label = block_scope.label, |
| | 3314 | .val = then_value, |
| | 3315 | }); |
| | 3316 | |
| | 3317 | const minuend = container_node; |
| | 3318 | const signed_size = try Tag.int_cast.create(c.arena, .{ |
| | 3319 | .lhs = try Tag.identifier.create(c.arena, "isize"), |
| | 3320 | .rhs = tmp_ref, |
| | 3321 | }); |
| | 3322 | const to_cast = try Tag.add_wrap.create(c.arena, .{ |
| | 3323 | .lhs = signed_size, |
| | 3324 | .rhs = try Tag.negate.create(c.arena, Tag.one_literal.init()), |
| | 3325 | }); |
| | 3326 | const bitcast_node = try Tag.bit_cast.create(c.arena, .{ |
| | 3327 | .lhs = try Tag.identifier.create(c.arena, "usize"), |
| | 3328 | .rhs = to_cast, |
| | 3329 | }); |
| | 3330 | const subtrahend = try Tag.bit_not.create(c.arena, bitcast_node); |
| | 3331 | const difference = try Tag.sub.create(c.arena, .{ |
| | 3332 | .lhs = minuend, |
| | 3333 | .rhs = subtrahend, |
| | 3334 | }); |
| | 3335 | const else_body = try Tag.break_val.create(c.arena, .{ |
| | 3336 | .label = block_scope.label, |
| | 3337 | .val = difference, |
| | 3338 | }); |
| | 3339 | |
| | 3340 | const if_node = try Tag.@"if".create(c.arena, .{ |
| | 3341 | .cond = cond_node, |
| | 3342 | .then = then_body, |
| | 3343 | .@"else" = else_body, |
| | 3344 | }); |
| | 3345 | |
| | 3346 | try block_scope.statements.append(if_node); |
| | 3347 | const block_node = try block_scope.complete(c); |
| | 3348 | |
| | 3349 | const derefed = try Tag.deref.create(c.arena, block_node); |
| | 3350 | |
| | 3351 | return maybeSuppressResult(c, &block_scope.base, result_used, derefed); |
| | 3352 | } |
| | 3353 | |
| 3276 | fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!Node { | 3354 | fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!Node { |
| 3277 | var base_stmt = stmt.getBase(); | 3355 | const base_stmt = stmt.getBase(); |
| | 3356 | const base_qt = getExprQualType(c, base_stmt); |
| | 3357 | const is_vector = cIsVector(base_qt); |
| | 3358 | |
| | 3359 | const subscr_expr = stmt.getIdx(); |
| | 3360 | const subscr_qt = getExprQualType(c, subscr_expr); |
| | 3361 | const is_longlong = cIsLongLongInteger(subscr_qt); |
| | 3362 | const is_signed = cIsSignedInteger(subscr_qt); |
| 3278 | | 3363 | |
| 3279 | // Unwrap the base statement if it's an array decayed to a bare pointer type | 3364 | // Unwrap the base statement if it's an array decayed to a bare pointer type |
| 3280 | // so that we index the array itself | 3365 | // so that we index the array itself |
| | 3366 | var unwrapped_base = base_stmt; |
| 3281 | if (@ptrCast(*const clang.Stmt, base_stmt).getStmtClass() == .ImplicitCastExprClass) { | 3367 | if (@ptrCast(*const clang.Stmt, base_stmt).getStmtClass() == .ImplicitCastExprClass) { |
| 3282 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, base_stmt); | 3368 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, base_stmt); |
| 3283 | | 3369 | |
| 3284 | if (implicit_cast.getCastKind() == .ArrayToPointerDecay) { | 3370 | if (implicit_cast.getCastKind() == .ArrayToPointerDecay) { |
| 3285 | base_stmt = implicit_cast.getSubExpr(); | 3371 | unwrapped_base = implicit_cast.getSubExpr(); |
| 3286 | } | 3372 | } |
| 3287 | } | 3373 | } |
| 3288 | | 3374 | |
| 3289 | const container_node = try transExpr(c, scope, base_stmt, .used); | 3375 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3290 | | 3376 | // See discussion at https://github.com/ziglang/zig/pull/8589 |
| 3291 | // cast if the index is long long or signed | 3377 | if (is_signed and (base_stmt == unwrapped_base) and !is_vector) return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); |
| 3292 | const subscr_expr = stmt.getIdx(); | | |
| 3293 | const qt = getExprQualType(c, subscr_expr); | | |
| 3294 | const is_longlong = cIsLongLongInteger(qt); | | |
| 3295 | const is_signed = cIsSignedInteger(qt); | | |
| 3296 | | 3378 | |
| | 3379 | const container_node = try transExpr(c, scope, unwrapped_base, .used); |
| 3297 | const rhs = if (is_longlong or is_signed) blk: { | 3380 | const rhs = if (is_longlong or is_signed) blk: { |
| 3298 | // check if long long first so that signed long long doesn't just become unsigned long long | 3381 | // check if long long first so that signed long long doesn't just become unsigned long long |
| 3299 | var typeid_node = if (is_longlong) try Tag.identifier.create(c.arena, "usize") else try transQualTypeIntWidthOf(c, qt, false); | 3382 | const typeid_node = if (is_longlong) try Tag.identifier.create(c.arena, "usize") else try transQualTypeIntWidthOf(c, subscr_qt, false); |
| 3300 | break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) }); | 3383 | break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) }); |
| 3301 | } else try transExpr(c, scope, subscr_expr, .used); | 3384 | } else try transExpr(c, scope, subscr_expr, .used); |
| 3302 | | 3385 | |