-
Notifications
You must be signed in to change notification settings - Fork 143
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Description
Struct compound literals currently only capture the first field value, ignoring subsequent fields. This severely limits their usefulness and violates C99 semantics. Array compound literals also have non-standard behavior that needs correction.
Current Bug
// Only first field is captured
struct point { int x, y; };
struct point p = (struct point){10, 20}; // y is lost, becomes 0
// Array compound literals broken
int *arr = (int[]){1, 2, 3, 4, 5}; // Non-standard behavior
C99 Standard Reference
C99 §6.5.2.5 Compound literals:
A compound literal provides an unnamed object whose value is given by the initializer list.
The entire initializer list must be processed, not just the first element.
Root Cause Analysis
In src/parser.c
, the compound literal parsing only processes one field:
// Current broken implementation
if (is_struct) {
read_parameter_list_decl(); // Only reads one value!
// Missing: loop to read all fields
}
Proposed Fix
1. Complete Struct Compound Literal Parsing
// src/parser.c - Fix compound literal parsing
void read_compound_literal(type_t *type) {
lex_expect('{');
if (type->base_type == TYPE_struct) {
parse_struct_compound_literal(type);
} else if (type->base_type == TYPE_array) {
parse_array_compound_literal(type);
} else {
error("compound literal requires struct or array type");
}
lex_expect('}');
}
void parse_struct_compound_literal(type_t *struct_type) {
// Allocate temporary storage for the struct
var_t *temp = add_tmp_var(current_block, "compound_lit", struct_type);
int field_index = 0;
struct_field_t *field = struct_type->fields;
while (!lex_peek_token('}')) {
if (field_index > 0) {
if (!lex_accept(',')) {
break; // No more initializers
}
}
// Check for designated initializer
if (lex_peek_token('.')) {
field = parse_designated_field_init(struct_type);
}
if (!field) {
error("too many initializers for struct");
break;
}
// Parse initializer expression
read_expr();
var_t *value = pop_var();
// Generate store to field
var_t *field_ptr = get_struct_field_ptr(temp, field);
emit_store(field_ptr, value, field->type);
// Move to next field (if not designated)
if (!designated) {
field = field->next;
field_index++;
}
}
// Initialize remaining fields to zero
while (field) {
var_t *field_ptr = get_struct_field_ptr(temp, field);
emit_store(field_ptr, zero_value(field->type), field->type);
field = field->next;
}
push_var(temp);
}
2. Fix Array Compound Literals
void parse_array_compound_literal(type_t *array_type) {
// Count elements first (if not specified)
int element_count = 0;
if (array_type->array_size == 0) {
element_count = count_initializer_elements();
array_type->array_size = element_count;
} else {
element_count = array_type->array_size;
}
// Allocate array storage
var_t *temp = add_tmp_var(current_block, "array_lit", array_type);
int index = 0;
while (!lex_peek_token('}') && index < element_count) {
if (index > 0) {
if (!lex_accept(',')) {
break;
}
}
// Check for designated initializer
if (lex_peek_token('[')) {
index = parse_designated_index_init();
}
// Parse element
read_expr();
var_t *value = pop_var();
// Store to array element
var_t *elem_ptr = get_array_element_ptr(temp, index);
emit_store(elem_ptr, value, array_type->element_type);
index++;
}
// Zero remaining elements
while (index < element_count) {
var_t *elem_ptr = get_array_element_ptr(temp, index);
emit_store(elem_ptr, zero_value(array_type->element_type),
array_type->element_type);
index++;
}
push_var(temp);
}
3. Support Designated Initializers
struct_field_t *parse_designated_field_init(type_t *struct_type) {
lex_expect('.');
char *field_name = read_identifier();
lex_expect('=');
// Find field by name
struct_field_t *field = struct_type->fields;
while (field) {
if (strcmp(field->name, field_name) == 0) {
return field;
}
field = field->next;
}
error("no field '%s' in struct", field_name);
return NULL;
}
int parse_designated_index_init() {
lex_expect('[');
int index = read_constant_expression();
lex_expect(']');
lex_expect('=');
return index;
}
4. Storage Duration and Lifetime
// Compound literals have automatic storage duration (stack)
// unless they appear at file scope (static storage)
var_t *create_compound_literal_storage(type_t *type) {
if (current_scope == SCOPE_GLOBAL) {
// Static storage duration
return add_global_var(gen_label("compound"), type);
} else {
// Automatic storage duration
return add_local_var(current_func, gen_label("compound"), type);
}
}
Test Cases
// tests/compound_literal_test.c
void test_struct_compound_literals() {
struct point { int x, y; };
// Basic compound literal
struct point p1 = (struct point){10, 20};
assert(p1.x == 10);
assert(p1.y == 20); // Currently fails!
// Partial initialization
struct point p2 = (struct point){.x = 5};
assert(p2.x == 5);
assert(p2.y == 0); // Uninitialized fields -> 0
// Designated initializers
struct point p3 = (struct point){.y = 30, .x = 25};
assert(p3.x == 25);
assert(p3.y == 30);
// Compound literal in expression
int sum = ((struct point){100, 200}).x +
((struct point){100, 200}).y;
assert(sum == 300);
}
void test_array_compound_literals() {
// Basic array compound literal
int *arr1 = (int[]){1, 2, 3, 4, 5};
assert(arr1[0] == 1);
assert(arr1[4] == 5);
// With size specified
int *arr2 = (int[10]){1, 2, 3}; // Rest are 0
assert(arr2[0] == 1);
assert(arr2[3] == 0);
assert(arr2[9] == 0);
// Designated initializers
int *arr3 = (int[]){[0] = 10, [5] = 50, [2] = 20};
assert(arr3[0] == 10);
assert(arr3[2] == 20);
assert(arr3[5] == 50);
}
void test_nested_compound_literals() {
struct nested {
struct point { int x, y; } p;
int z;
};
struct nested n = (struct nested){
.p = (struct point){10, 20},
.z = 30
};
assert(n.p.x == 10);
assert(n.p.y == 20);
assert(n.z == 30);
}
void test_compound_literal_lifetime() {
int *get_array() {
return (int[]){1, 2, 3}; // Warning: returns local
}
// Compound literal has automatic storage duration
// Returning it is undefined behavior (like returning local array)
}
Implementation Priority
- Fix struct compound literals to capture all fields
- Fix array compound literals
- Add designated initializer support
- Ensure proper storage duration semantics
Success Criteria
- All struct fields captured in compound literals
- Array compound literals work correctly
- Designated initializers supported
- Proper storage duration (auto/static)
- No regression in existing code
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working