Skip to content

Commit a4aba54

Browse files
committed
Add tests for array literal pointer semantics
Add regression tests that verify pointer and decay semantics of array compound literals. The tests cover decay during initialization, passing array literals to functions that expect pointer arguments, pointer-typed ternary expressions involving literal branches, and correctness for char[] and short[] literals in simple computations. These tests confirm the behavior introduced by the refined compound literal semantics implemented in the preceding commit.
1 parent 11c6b59 commit a4aba54

File tree

6 files changed

+93
-20
lines changed

6 files changed

+93
-20
lines changed

src/parser.c

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ void parse_array_init(var_t *var,
4747
bool emit_code);
4848
void parse_array_compound_literal(var_t *var,
4949
block_t *parent,
50-
basic_block_t **bb,
51-
bool emit_code);
50+
basic_block_t **bb);
5251

5352
label_t *find_label(char *name)
5453
{
@@ -1335,8 +1334,7 @@ void parse_array_init(var_t *var,
13351334

13361335
void parse_array_compound_literal(var_t *var,
13371336
block_t *parent,
1338-
basic_block_t **bb,
1339-
bool emit_code)
1337+
basic_block_t **bb)
13401338
{
13411339
int elem_size = var->type->size;
13421340
int count = 0;
@@ -1349,16 +1347,16 @@ void parse_array_compound_literal(var_t *var,
13491347
var_t *value = opstack_pop();
13501348
if (count == 0)
13511349
var->init_val = value->init_val;
1352-
if (emit_code) {
1353-
var_t target = {0};
1354-
target.type = var->type;
1355-
target.ptr_level = 0;
1356-
var_t *store_val = resize_var(parent, bb, value, &target);
1357-
var_t *elem_addr =
1358-
compute_element_address(parent, bb, var, count, elem_size);
1359-
add_insn(parent, *bb, OP_write, NULL, elem_addr, store_val,
1360-
elem_size, NULL);
1361-
}
1350+
1351+
var_t target = {0};
1352+
target.type = var->type;
1353+
target.ptr_level = 0;
1354+
var_t *store_val = resize_var(parent, bb, value, &target);
1355+
var_t *elem_addr =
1356+
compute_element_address(parent, bb, var, count, elem_size);
1357+
add_insn(parent, *bb, OP_write, NULL, elem_addr, store_val,
1358+
elem_size, NULL);
1359+
13621360
count++;
13631361
if (!lex_accept(T_comma))
13641362
break;
@@ -1385,7 +1383,11 @@ bool is_pointer_like_value(var_t *var)
13851383
return var && (var->ptr_level || var->array_size ||
13861384
(var->type && var->type->ptr_level > 0));
13871385
}
1388-
1386+
/* Lower a compiler-emitted array literal placeholder (".tN" vars holding
1387+
* compound literals) into a scalar temporary when later IR expects a plain
1388+
* value instead of addressable storage. This keeps SSA joins uniform when
1389+
* only one branch originates from an array literal.
1390+
*/
13891391
var_t *scalarize_array_literal(block_t *parent,
13901392
basic_block_t **bb,
13911393
var_t *array_var,
@@ -1394,20 +1396,30 @@ var_t *scalarize_array_literal(block_t *parent,
13941396
if (!is_array_literal_placeholder(array_var))
13951397
return array_var;
13961398

1399+
/* Array literal placeholders carry the literal's natural type; default to
1400+
* int when the parser left the type unset.
1401+
*/
13971402
type_t *literal_type = array_var->type ? array_var->type : TY_int;
13981403
int literal_size = literal_type->size;
13991404
if (literal_size <= 0)
14001405
literal_size = TY_int->size;
14011406

1407+
/* A caller-provided hint (e.g., assignment target) dictates the result
1408+
* type when available so we reuse wider/narrower scalar destinations.
1409+
*/
14021410
type_t *result_type = hint_type ? hint_type : literal_type;
14031411
if (!result_type)
14041412
result_type = TY_int;
14051413

1414+
/* Create a new scalar temporary, giving it a unique name and copying over
1415+
* the literal data so downstream code can treat it like a normal value.
1416+
*/
14061417
var_t *scalar = require_typed_var(parent, result_type);
14071418
scalar->ptr_level = 0;
14081419
gen_name_to(scalar->var_name);
14091420
scalar->init_val = array_var->init_val;
14101421

1422+
/* Materialize the literal data into the scalar temporary via an OP_read. */
14111423
add_insn(parent, *bb, OP_read, scalar, array_var, NULL, literal_size, NULL);
14121424

14131425
return scalar;
@@ -2159,7 +2171,7 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
21592171
compound_var->array_size = 0;
21602172
add_insn(parent, *bb, OP_allocat, compound_var, NULL, NULL, 0,
21612173
NULL);
2162-
parse_array_compound_literal(compound_var, parent, bb, true);
2174+
parse_array_compound_literal(compound_var, parent, bb);
21632175

21642176
if (compound_var->array_size == 0) {
21652177
compound_var->init_val = 0;
@@ -3628,10 +3640,19 @@ void read_ternary_operation(block_t *parent, basic_block_t **bb)
36283640
bool true_ptr_like = is_pointer_like_value(true_val);
36293641
bool false_ptr_like = is_pointer_like_value(false_val);
36303642

3643+
/* The ternary result must look like whichever side is pointer-like. If the
3644+
* "true" expression is still a raw array literal but the "false" side is a
3645+
* plain scalar, materialize the literal now so both branches produce
3646+
* comparable scalar SSA values.
3647+
*/
36313648
if (true_array && !false_ptr_like)
36323649
true_val = scalarize_array_literal(parent, &then_, true_val,
36333650
false_val ? false_val->type : NULL);
36343651

3652+
/* Apply the same conversion symmetrically when only the false branch is a
3653+
* literal array. This prevents OP_assign from trying to move array storage
3654+
* into a scalar destination later in code generation.
3655+
*/
36353656
if (false_array && !true_ptr_like)
36363657
false_val = scalarize_array_literal(parent, &else_, false_val,
36373658
true_val ? true_val->type : NULL);

tests/driver.sh

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,28 @@ int main() {
733733
}
734734
EOF
735735

736+
# Test: Array compound literal decay to pointer in initializer
737+
try_ 0 << EOF
738+
int main(void) {
739+
int *arr = (int[]){1, 2, 3, 4, 5};
740+
return arr[0] != 1 || arr[4] != 5;
741+
}
742+
EOF
743+
744+
# Test: Passing array compound literal as pointer argument
745+
try_ 0 << EOF
746+
int sum(int *p, int n) {
747+
int s = 0;
748+
for (int i = 0; i < n; i++)
749+
s += p[i];
750+
return s;
751+
}
752+
int main(void) {
753+
int s = sum((int[]){1, 2, 3, 0, 0}, 3);
754+
return s != 6;
755+
}
756+
EOF
757+
736758
# Test: Complex expression with compound literals
737759
try_ 77 << EOF
738760
int main() {
@@ -4737,6 +4759,36 @@ int main() {
47374759
}
47384760
EOF
47394761

4762+
try_ 200 << EOF
4763+
int main(void) {
4764+
char *s = (char[]){'A', 'B', 'C', 'D', 'E'};
4765+
return s[0] + s[1] + s[4]; /* 65 + 66 + 69 */
4766+
}
4767+
EOF
4768+
4769+
try_ 6 << EOF
4770+
int main(void) {
4771+
short *s = (short[]){1, 2, 3, 4, 5};
4772+
return s[0] + s[4];
4773+
}
4774+
EOF
4775+
4776+
try_ 60 << EOF
4777+
int main(void) {
4778+
int arr[] = {10, 20, 30, 40, 50};
4779+
int *selected = 1 ? arr : (int[]){1, 2, 3, 4, 5};
4780+
return selected[0] + selected[4];
4781+
}
4782+
EOF
4783+
4784+
try_ 6 << EOF
4785+
int main(void) {
4786+
int arr[] = {10, 20, 30, 40, 50};
4787+
int *selected = 0 ? arr : (int[]){1, 2, 3, 4, 5};
4788+
return selected[0] + selected[4];
4789+
}
4790+
EOF
4791+
47404792
try_ 120 << EOF
47414793
int main() {
47424794
/* Complex expression with mixed compound literals */

tests/snapshots/fib-arm-static.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/fib-riscv-static.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-arm-static.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-riscv-static.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)