Skip to content

Commit

Permalink
Parser: Coerce array members properly from strings
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsan901998 committed Nov 9, 2023
1 parent 0b0b60f commit c141489
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3356,8 +3356,8 @@ fn initializerItem(p: *Parser, il: *InitList, init_ty: Type) Error!bool {

excess: {
if (index_hint) |*hint| {
if (try p.findScalarInitializerAt(&cur_il, &cur_ty, res.ty, first_tok, hint)) break :excess;
} else if (try p.findScalarInitializer(&cur_il, &cur_ty, res.ty, first_tok)) break :excess;
if (try p.findScalarInitializerAt(&cur_il, &cur_ty, &res, first_tok, hint)) break :excess;
} else if (try p.findScalarInitializer(&cur_il, &cur_ty, &res, first_tok)) break :excess;

if (designation) break :excess;
if (!warned_excess) try p.errTok(if (init_ty.isArray()) .excess_array_init else .excess_struct_init, first_tok);
Expand Down Expand Up @@ -3407,7 +3407,7 @@ fn initializerItem(p: *Parser, il: *InitList, init_ty: Type) Error!bool {
}

/// Returns true if the value is unused.
fn findScalarInitializerAt(p: *Parser, il: **InitList, ty: *Type, actual_ty: Type, first_tok: TokenIndex, start_index: *u64) Error!bool {
fn findScalarInitializerAt(p: *Parser, il: **InitList, ty: *Type, res: *Result, first_tok: TokenIndex, start_index: *u64) Error!bool {
if (ty.isArray()) {
if (il.*.node != .none) return false;
start_index.* += 1;
Expand All @@ -3423,7 +3423,7 @@ fn findScalarInitializerAt(p: *Parser, il: **InitList, ty: *Type, actual_ty: Typ
if (start_index.* < elem_count) {
ty.* = elem_ty;
il.* = try arr_il.find(p.gpa, start_index.*);
_ = try p.findScalarInitializer(il, ty, actual_ty, first_tok);
_ = try p.findScalarInitializer(il, ty, res, first_tok);
return true;
}
return false;
Expand All @@ -3441,7 +3441,7 @@ fn findScalarInitializerAt(p: *Parser, il: **InitList, ty: *Type, actual_ty: Typ
const field = fields[@intCast(start_index.*)];
ty.* = field.ty;
il.* = try struct_il.find(p.gpa, start_index.*);
_ = try p.findScalarInitializer(il, ty, actual_ty, first_tok);
_ = try p.findScalarInitializer(il, ty, res, first_tok);
return true;
}
return false;
Expand All @@ -3452,7 +3452,8 @@ fn findScalarInitializerAt(p: *Parser, il: **InitList, ty: *Type, actual_ty: Typ
}

/// Returns true if the value is unused.
fn findScalarInitializer(p: *Parser, il: **InitList, ty: *Type, actual_ty: Type, first_tok: TokenIndex) Error!bool {
fn findScalarInitializer(p: *Parser, il: **InitList, ty: *Type, res: *Result, first_tok: TokenIndex) Error!bool {
const actual_ty = res.ty;
if (ty.isArray() or ty.isComplex()) {
if (il.*.node != .none) return false;
const start_index = il.*.list.items.len;
Expand All @@ -3470,7 +3471,7 @@ fn findScalarInitializer(p: *Parser, il: **InitList, ty: *Type, actual_ty: Type,
ty.* = elem_ty;
il.* = try arr_il.find(p.gpa, index);
if (il.*.node == .none and actual_ty.eql(elem_ty, p.comp, false)) return true;
if (try p.findScalarInitializer(il, ty, actual_ty, first_tok)) return true;
if (try p.findScalarInitializer(il, ty, res, first_tok)) return true;
}
return false;
} else if (ty.get(.@"struct")) |struct_ty| {
Expand All @@ -3490,7 +3491,8 @@ fn findScalarInitializer(p: *Parser, il: **InitList, ty: *Type, actual_ty: Type,
ty.* = field.ty;
il.* = try struct_il.find(p.gpa, index);
if (il.*.node == .none and actual_ty.eql(field.ty, p.comp, false)) return true;
if (try p.findScalarInitializer(il, ty, actual_ty, first_tok)) return true;
if (il.*.node == .none and try p.coerceArrayInit(res, first_tok, ty.*)) return true;
if (try p.findScalarInitializer(il, ty, res, first_tok)) return true;
}
return false;
} else if (ty.get(.@"union")) |union_ty| {
Expand All @@ -3503,7 +3505,8 @@ fn findScalarInitializer(p: *Parser, il: **InitList, ty: *Type, actual_ty: Type,
ty.* = union_ty.data.record.fields[0].ty;
il.* = try il.*.find(p.gpa, 0);
// if (il.*.node == .none and actual_ty.eql(ty, p.comp, false)) return true;
if (try p.findScalarInitializer(il, ty, actual_ty, first_tok)) return true;
if (try p.coerceArrayInit(res, first_tok, ty.*)) return true;
if (try p.findScalarInitializer(il, ty, res, first_tok)) return true;
return false;
}
return il.*.node == .none;
Expand Down
18 changes: 18 additions & 0 deletions test/cases/initializers.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,23 @@ void quux(void) {
long *y = &x;
unsigned int *z = &x;
}
struct S2 {
char bytes[32];
};
union U {
char bytes[32];
};
union U2 {
int a;
char bytes[32];
};

void array_members(void) {
struct S2 s = (struct S2){"ABC"};
union U u = (union U){"ABC"};
union U2 u2 = (union U2){"ABC"};
char b[32] = (char[32]){"ABC"};
}

#define TESTS_SKIPPED 3
#define EXPECTED_ERRORS "initializers.c:2:17: error: variable-sized object may not be initialized" \
Expand Down Expand Up @@ -184,4 +201,5 @@ void quux(void) {
"initializers.c:129:17: error: initializing 'void *' from incompatible type 'struct Foo'" \
"initializers.c:131:15: warning: incompatible pointer types initializing 'long *' from incompatible type 'int *' [-Wincompatible-pointer-types]" \
"initializers.c:132:23: warning: incompatible pointer types initializing 'unsigned int *' from incompatible type 'int *' converts between pointers to integer types with different sign [-Wpointer-sign]" \
"initializers.c:148:30: warning: implicit pointer to integer conversion from 'char *' to 'int' [-Wint-conversion]" \

0 comments on commit c141489

Please sign in to comment.