Skip to content

Commit 1495cf8

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 87879b0 commit 1495cf8

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
@@ -1380,6 +1380,12 @@ bool is_array_literal_placeholder(var_t *var)
13801380
var->var_name[0] == '.';
13811381
}
13821382

1383+
bool is_pointer_like_value(var_t *var)
1384+
{
1385+
return var && (var->ptr_level || var->array_size ||
1386+
(var->type && var->type->ptr_level > 0));
1387+
}
1388+
13831389
var_t *scalarize_array_literal(block_t *parent,
13841390
basic_block_t **bb,
13851391
var_t *array_var,
@@ -1388,20 +1394,21 @@ var_t *scalarize_array_literal(block_t *parent,
13881394
if (!is_array_literal_placeholder(array_var))
13891395
return array_var;
13901396

1391-
type_t *elem_type = hint_type ? hint_type : array_var->type;
1392-
if (!elem_type)
1393-
elem_type = TY_int;
1397+
type_t *literal_type = array_var->type ? array_var->type : TY_int;
1398+
int literal_size = literal_type->size;
1399+
if (literal_size <= 0)
1400+
literal_size = TY_int->size;
13941401

1395-
int elem_size = elem_type->size;
1396-
if (elem_size <= 0)
1397-
elem_size = TY_int->size;
1402+
type_t *result_type = hint_type ? hint_type : literal_type;
1403+
if (!result_type)
1404+
result_type = TY_int;
13981405

1399-
var_t *scalar = require_typed_var(parent, elem_type);
1406+
var_t *scalar = require_typed_var(parent, result_type);
14001407
scalar->ptr_level = 0;
14011408
gen_name_to(scalar->var_name);
14021409
scalar->init_val = array_var->init_val;
14031410

1404-
add_insn(parent, *bb, OP_read, scalar, array_var, NULL, elem_size, NULL);
1411+
add_insn(parent, *bb, OP_read, scalar, array_var, NULL, literal_size, NULL);
14051412

14061413
return scalar;
14071414
}
@@ -1703,8 +1710,6 @@ void read_func_parameters(func_t *func, block_t *parent, basic_block_t **bb)
17031710
if (!target->ptr_level && !target->array_size)
17041711
param = scalarize_array_literal(parent, bb, param,
17051712
target->type);
1706-
} else if (func->va_args) {
1707-
param = scalarize_array_literal(parent, bb, param, TY_int);
17081713
}
17091714
}
17101715
/* Handle parameter type conversion for direct calls.
@@ -2612,20 +2617,14 @@ void handle_pointer_arithmetic(block_t *parent,
26122617
}
26132618

26142619
/* Check if both have ptr_level or typedef pointer type */
2615-
bool rs1_is_ptr = (orig_rs1->ptr_level > 0) ||
2616-
(orig_rs1->type && orig_rs1->type->ptr_level > 0);
2617-
bool rs2_is_ptr = (orig_rs2->ptr_level > 0) ||
2618-
(orig_rs2->type && orig_rs2->type->ptr_level > 0);
2620+
bool rs1_is_ptr = is_pointer_like_value(orig_rs1);
2621+
bool rs2_is_ptr = is_pointer_like_value(orig_rs2);
26192622

26202623
/* If variable lookup failed, check the passed variables directly */
2621-
if (!rs1_is_ptr) {
2622-
rs1_is_ptr =
2623-
(rs1->ptr_level > 0) || (rs1->type && rs1->type->ptr_level > 0);
2624-
}
2625-
if (!rs2_is_ptr) {
2626-
rs2_is_ptr =
2627-
(rs2->ptr_level > 0) || (rs2->type && rs2->type->ptr_level > 0);
2628-
}
2624+
if (!rs1_is_ptr)
2625+
rs1_is_ptr = is_pointer_like_value(rs1);
2626+
if (!rs2_is_ptr)
2627+
rs2_is_ptr = is_pointer_like_value(rs2);
26292628

26302629
if (rs1_is_ptr && rs2_is_ptr) {
26312630
/* Both are pointers - this is pointer difference */
@@ -2704,11 +2703,11 @@ void handle_pointer_arithmetic(block_t *parent,
27042703
}
27052704
}
27062705
/* Determine which operand is the pointer for regular pointer arithmetic */
2707-
if (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0)) {
2706+
if (is_pointer_like_value(rs1)) {
27082707
ptr_var = rs1;
27092708
int_var = rs2;
27102709
element_size = get_pointer_element_size(rs1);
2711-
} else if (rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0)) {
2710+
} else if (is_pointer_like_value(rs2)) {
27122711
/* Only for addition (p + n == n + p) */
27132712
if (op == OP_add) {
27142713
ptr_var = rs2;
@@ -2755,8 +2754,7 @@ bool is_pointer_operation(opcode_t op, var_t *rs1, var_t *rs2)
27552754
if (op != OP_add && op != OP_sub)
27562755
return false;
27572756

2758-
return (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0) ||
2759-
rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0));
2757+
return is_pointer_like_value(rs1) || is_pointer_like_value(rs2);
27602758
}
27612759

27622760
/* Helper function to check if a variable is a pointer based on its declaration
@@ -2949,22 +2947,31 @@ void read_expr(block_t *parent, basic_block_t **bb)
29492947
rs2 = opstack_pop();
29502948
rs1 = opstack_pop();
29512949

2950+
bool rs1_is_placeholder = is_array_literal_placeholder(rs1);
2951+
bool rs2_is_placeholder = is_array_literal_placeholder(rs2);
2952+
bool rs1_is_ptr_like = is_pointer_like_value(rs1);
2953+
bool rs2_is_ptr_like = is_pointer_like_value(rs2);
2954+
bool pointer_context = (rs1_is_ptr_like && !rs1_is_placeholder) ||
2955+
(rs2_is_ptr_like && !rs2_is_placeholder);
2956+
29522957
/* Pointer arithmetic handling */
2953-
if (is_pointer_operation(top_op, rs1, rs2)) {
2958+
if (pointer_context && is_pointer_operation(top_op, rs1, rs2)) {
29542959
handle_pointer_arithmetic(parent, bb, top_op, rs1, rs2);
29552960
continue; /* skip normal processing */
29562961
}
29572962

2958-
bool rs1_is_ptr_like = rs1 && (rs1->ptr_level || rs1->array_size);
2959-
bool rs2_is_ptr_like = rs2 && (rs2->ptr_level || rs2->array_size);
2960-
2961-
if (is_array_literal_placeholder(rs1) && !rs2_is_ptr_like)
2962-
rs1 = scalarize_array_literal(parent, bb, rs1,
2963-
rs2 && rs2->type ? rs2->type : NULL);
2963+
if (rs1_is_placeholder && rs2_is_placeholder) {
2964+
rs1 = scalarize_array_literal(parent, bb, rs1, NULL);
2965+
rs2 = scalarize_array_literal(parent, bb, rs2, NULL);
2966+
} else {
2967+
if (rs1_is_placeholder && !rs2_is_ptr_like)
2968+
rs1 = scalarize_array_literal(
2969+
parent, bb, rs1, rs2 && rs2->type ? rs2->type : NULL);
29642970

2965-
if (is_array_literal_placeholder(rs2) && !rs1_is_ptr_like)
2966-
rs2 = scalarize_array_literal(parent, bb, rs2,
2967-
rs1 && rs1->type ? rs1->type : NULL);
2971+
if (rs2_is_placeholder && !rs1_is_ptr_like)
2972+
rs2 = scalarize_array_literal(
2973+
parent, bb, rs2, rs1 && rs1->type ? rs1->type : NULL);
2974+
}
29682975
/* Constant folding for binary operations */
29692976
if (rs1 && rs2 && rs1->init_val && !rs1->ptr_level && !rs1->is_global &&
29702977
rs2->init_val && !rs2->ptr_level && !rs2->is_global) {

0 commit comments

Comments
 (0)