| ... | ... | @@ -3273,30 +3273,113 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re |
| 3273 | 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 | 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 | 3364 | // Unwrap the base statement if it's an array decayed to a bare pointer type |
| 3280 | 3365 | // so that we index the array itself |
| 3366 | var unwrapped_base = base_stmt; |
| 3281 | 3367 | if (@ptrCast(*const clang.Stmt, base_stmt).getStmtClass() == .ImplicitCastExprClass) { |
| 3282 | 3368 | const implicit_cast = @ptrCast(*const clang.ImplicitCastExpr, base_stmt); |
| 3283 | 3369 | |
| 3284 | 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); |
| 3290 | | |
| 3291 | | // cast if the index is long long or signed |
| 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); |
| 3375 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3376 | // See discussion at https://github.com/ziglang/zig/pull/8589 |
| 3377 | if (is_signed and (base_stmt == unwrapped_base) and !is_vector) return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); |
| 3296 | 3378 | |
| 3379 | const container_node = try transExpr(c, scope, unwrapped_base, .used); |
| 3297 | 3380 | const rhs = if (is_longlong or is_signed) blk: { |
| 3298 | 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 | 3383 | break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) }); |
| 3301 | 3384 | } else try transExpr(c, scope, subscr_expr, .used); |
| 3302 | 3385 | |