Skip to content

Commit e57c5c6

Browse files
committed
Fix incorrect scalarization in variadic and pointer contexts
Update `scalarize_array_literal` to read using the literal’s element size while still allowing callers to select the final result type. Stop collapsing array literals in variadic call arguments and pointer arithmetic operands merely because the opposite operand is an integer. This ensures array literals decay to pointers when required rather than being forced into scalars. For literal-plus-literal arithmetic, preserve the historical behavior by computing a scalar sum of the first elements, while still honoring proper pointer arithmetic when a real pointer participates.
1 parent 62211b5 commit e57c5c6

File tree

1 file changed

+43
-36
lines changed

1 file changed

+43
-36
lines changed

src/parser.c

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,12 @@ bool is_array_literal_placeholder(var_t *var)
13331333
var->var_name[0] == '.';
13341334
}
13351335

1336+
bool is_pointer_like_value(var_t *var)
1337+
{
1338+
return var && (var->ptr_level || var->array_size ||
1339+
(var->type && var->type->ptr_level > 0));
1340+
}
1341+
13361342
var_t *scalarize_array_literal(block_t *parent,
13371343
basic_block_t **bb,
13381344
var_t *array_var,
@@ -1341,20 +1347,21 @@ var_t *scalarize_array_literal(block_t *parent,
13411347
if (!is_array_literal_placeholder(array_var))
13421348
return array_var;
13431349

1344-
type_t *elem_type = hint_type ? hint_type : array_var->type;
1345-
if (!elem_type)
1346-
elem_type = TY_int;
1350+
type_t *literal_type = array_var->type ? array_var->type : TY_int;
1351+
int literal_size = literal_type->size;
1352+
if (literal_size <= 0)
1353+
literal_size = TY_int->size;
13471354

1348-
int elem_size = elem_type->size;
1349-
if (elem_size <= 0)
1350-
elem_size = TY_int->size;
1355+
type_t *result_type = hint_type ? hint_type : literal_type;
1356+
if (!result_type)
1357+
result_type = TY_int;
13511358

1352-
var_t *scalar = require_typed_var(parent, elem_type);
1359+
var_t *scalar = require_typed_var(parent, result_type);
13531360
scalar->ptr_level = 0;
13541361
gen_name_to(scalar->var_name);
13551362
scalar->init_val = array_var->init_val;
13561363

1357-
add_insn(parent, *bb, OP_read, scalar, array_var, NULL, elem_size, NULL);
1364+
add_insn(parent, *bb, OP_read, scalar, array_var, NULL, literal_size, NULL);
13581365

13591366
return scalar;
13601367
}
@@ -1656,8 +1663,6 @@ void read_func_parameters(func_t *func, block_t *parent, basic_block_t **bb)
16561663
if (!target->ptr_level && !target->array_size)
16571664
param = scalarize_array_literal(parent, bb, param,
16581665
target->type);
1659-
} else if (func->va_args) {
1660-
param = scalarize_array_literal(parent, bb, param, TY_int);
16611666
}
16621667
}
16631668
/* Handle parameter type conversion for direct calls.
@@ -2565,20 +2570,14 @@ void handle_pointer_arithmetic(block_t *parent,
25652570
}
25662571

25672572
/* Check if both have ptr_level or typedef pointer type */
2568-
bool rs1_is_ptr = (orig_rs1->ptr_level > 0) ||
2569-
(orig_rs1->type && orig_rs1->type->ptr_level > 0);
2570-
bool rs2_is_ptr = (orig_rs2->ptr_level > 0) ||
2571-
(orig_rs2->type && orig_rs2->type->ptr_level > 0);
2573+
bool rs1_is_ptr = is_pointer_like_value(orig_rs1);
2574+
bool rs2_is_ptr = is_pointer_like_value(orig_rs2);
25722575

25732576
/* If variable lookup failed, check the passed variables directly */
2574-
if (!rs1_is_ptr) {
2575-
rs1_is_ptr =
2576-
(rs1->ptr_level > 0) || (rs1->type && rs1->type->ptr_level > 0);
2577-
}
2578-
if (!rs2_is_ptr) {
2579-
rs2_is_ptr =
2580-
(rs2->ptr_level > 0) || (rs2->type && rs2->type->ptr_level > 0);
2581-
}
2577+
if (!rs1_is_ptr)
2578+
rs1_is_ptr = is_pointer_like_value(rs1);
2579+
if (!rs2_is_ptr)
2580+
rs2_is_ptr = is_pointer_like_value(rs2);
25822581

25832582
if (rs1_is_ptr && rs2_is_ptr) {
25842583
/* Both are pointers - this is pointer difference */
@@ -2657,11 +2656,11 @@ void handle_pointer_arithmetic(block_t *parent,
26572656
}
26582657
}
26592658
/* Determine which operand is the pointer for regular pointer arithmetic */
2660-
if (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0)) {
2659+
if (is_pointer_like_value(rs1)) {
26612660
ptr_var = rs1;
26622661
int_var = rs2;
26632662
element_size = get_pointer_element_size(rs1);
2664-
} else if (rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0)) {
2663+
} else if (is_pointer_like_value(rs2)) {
26652664
/* Only for addition (p + n == n + p) */
26662665
if (op == OP_add) {
26672666
ptr_var = rs2;
@@ -2708,8 +2707,7 @@ bool is_pointer_operation(opcode_t op, var_t *rs1, var_t *rs2)
27082707
if (op != OP_add && op != OP_sub)
27092708
return false;
27102709

2711-
return (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0) ||
2712-
rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0));
2710+
return is_pointer_like_value(rs1) || is_pointer_like_value(rs2);
27132711
}
27142712

27152713
/* Helper function to check if a variable is a pointer based on its declaration
@@ -2902,22 +2900,31 @@ void read_expr(block_t *parent, basic_block_t **bb)
29022900
rs2 = opstack_pop();
29032901
rs1 = opstack_pop();
29042902

2903+
bool rs1_is_placeholder = is_array_literal_placeholder(rs1);
2904+
bool rs2_is_placeholder = is_array_literal_placeholder(rs2);
2905+
bool rs1_is_ptr_like = is_pointer_like_value(rs1);
2906+
bool rs2_is_ptr_like = is_pointer_like_value(rs2);
2907+
bool pointer_context = (rs1_is_ptr_like && !rs1_is_placeholder) ||
2908+
(rs2_is_ptr_like && !rs2_is_placeholder);
2909+
29052910
/* Pointer arithmetic handling */
2906-
if (is_pointer_operation(top_op, rs1, rs2)) {
2911+
if (pointer_context && is_pointer_operation(top_op, rs1, rs2)) {
29072912
handle_pointer_arithmetic(parent, bb, top_op, rs1, rs2);
29082913
continue; /* skip normal processing */
29092914
}
29102915

2911-
bool rs1_is_ptr_like = rs1 && (rs1->ptr_level || rs1->array_size);
2912-
bool rs2_is_ptr_like = rs2 && (rs2->ptr_level || rs2->array_size);
2913-
2914-
if (is_array_literal_placeholder(rs1) && !rs2_is_ptr_like)
2915-
rs1 = scalarize_array_literal(parent, bb, rs1,
2916-
rs2 && rs2->type ? rs2->type : NULL);
2916+
if (rs1_is_placeholder && rs2_is_placeholder) {
2917+
rs1 = scalarize_array_literal(parent, bb, rs1, NULL);
2918+
rs2 = scalarize_array_literal(parent, bb, rs2, NULL);
2919+
} else {
2920+
if (rs1_is_placeholder && !rs2_is_ptr_like)
2921+
rs1 = scalarize_array_literal(
2922+
parent, bb, rs1, rs2 && rs2->type ? rs2->type : NULL);
29172923

2918-
if (is_array_literal_placeholder(rs2) && !rs1_is_ptr_like)
2919-
rs2 = scalarize_array_literal(parent, bb, rs2,
2920-
rs1 && rs1->type ? rs1->type : NULL);
2924+
if (rs2_is_placeholder && !rs1_is_ptr_like)
2925+
rs2 = scalarize_array_literal(
2926+
parent, bb, rs2, rs1 && rs1->type ? rs1->type : NULL);
2927+
}
29212928
/* Constant folding for binary operations */
29222929
if (rs1 && rs2 && rs1->init_val && !rs1->ptr_level && !rs1->is_global &&
29232930
rs2->init_val && !rs2->ptr_level && !rs2->is_global) {

0 commit comments

Comments
 (0)