History

struct-init: Implement initializing subaggregates

E.g. "struct { struct S s; int a;} = { others, 42 };" if 'others' is also a 'struct S'. Also when the value is a compound literal. See added testcases.

Michael Matz committed 10 years ago

Commit ed7d5461 parent 968bccd4 files · +226 −40Browse files

Unified · Split

4 files
  1. tccgen.c +59 −39
  2. tests/tests2/86-struct-init.c +139 −0
  3. tests/tests2/86-struct-init.expect +27 −0
  4. tests/tests2/Makefile +1 −1
tccgen.c+59−39
@@ -74,7 +74,7 @@ static int is_compatible_types(CType *type1, CType *type2); · 73 unmodified lines
7474 static int parse_btype(CType *type, AttributeDef *ad);
7575 static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
7676 static void parse_expr_type(CType *type);
77−static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
77+static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only, int have_elem);
7878 static void block(int *bsym, int *csym, int is_expr);
7979 static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
8080 static int decl0(int l, int is_for_loop_init);
@@ -5650,13 +5650,37 @@ static void block(int *bsym, int *csym, int is_expr) · 5569 unmodified lines
56505650 }
56515651 }
56525652
5653+#define EXPR_VAL 0
5654+#define EXPR_CONST 1
5655+#define EXPR_ANY 2
5656+
5657+static void parse_init_elem(int expr_type)
5658+{
5659+ int saved_global_expr;
5660+ switch(expr_type) {
5661+ case EXPR_CONST:
5662+ /* compound literals must be allocated globally in this case */
5663+ saved_global_expr = global_expr;
5664+ global_expr = 1;
5665+ expr_const1();
5666+ global_expr = saved_global_expr;
5667+ /* NOTE: symbols are accepted */
5668+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
5669+ tcc_error("initializer element is not constant");
5670+ break;
5671+ case EXPR_ANY:
5672+ expr_eq();
5673+ break;
5674+ }
5675+}
5676+
56535677 /* t is the array or struct type. c is the array or struct
56545678 address. cur_index/cur_field is the pointer to the current
56555679 value. 'size_only' is true if only size info is needed (only used
56565680 in arrays) */
56575681 static void decl_designator(CType *type, Section *sec, unsigned long c,
56585682 int *cur_index, Sym **cur_field,
5659− int size_only)
5683+ int size_only, int have_elem)
56605684 {
56615685 Sym *s, *f;
56625686 int notfirst, index, index_last, align, l, nb_elems, elem_size;
@@ -5748,7 +5772,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, · 85 unmodified lines
57485772 c += f->c;
57495773 }
57505774 }
5751− decl_initializer(type, sec, c, 0, size_only);
5775+ decl_initializer(type, sec, c, 0, size_only, have_elem);
57525776
57535777 /* XXX: make it more general */
57545778 if (!size_only && nb_elems > 1) {
@@ -5770,30 +5794,6 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
57705794 }
57715795 }
57725796
5773−#define EXPR_VAL 0
5774−#define EXPR_CONST 1
5775−#define EXPR_ANY 2
5776−
5777−static void parse_init_elem(int expr_type)
5778−{
5779− int saved_global_expr;
5780− switch(expr_type) {
5781− case EXPR_CONST:
5782− /* compound literals must be allocated globally in this case */
5783− saved_global_expr = global_expr;
5784− global_expr = 1;
5785− expr_const1();
5786− global_expr = saved_global_expr;
5787− /* NOTE: symbols are accepted */
5788− if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
5789− tcc_error("initializer element is not constant");
5790− break;
5791− case EXPR_ANY:
5792− expr_eq();
5793− break;
5794− }
5795−}
5796−
57975797 /* store a value or an expression directly in global data or in local array */
57985798 static void init_putv(CType *type, Section *sec, unsigned long c,
57995799 int v, int expr_type)
@@ -5957,7 +5957,7 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) · 157 unmodified lines
59575957 dimension implicit array init handling). 'size_only' is true if
59585958 size only evaluation is wanted (only for arrays). */
59595959 static void decl_initializer(CType *type, Section *sec, unsigned long c,
5960− int first, int size_only)
5960+ int first, int size_only, int have_elem)
59615961 {
59625962 int index, array_length, n, no_oblock, nb, parlevel, parlevel1, i;
59635963 int size1, align1, expr_type;
@@ -5979,6 +5979,13 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
59795979 gen_vla_sp_save(c);
59805980 vla_sp_loc = c;
59815981 vlas_in_scope++;
5982+ } else if (!have_elem && tok != '{' && tok != TOK_LSTR &&
5983+ tok != TOK_STR && !size_only) {
5984+ parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
5985+ have_elem = 1;
5986+ }
5987+
5988+ if (type->t & VT_VLA) {
59825989 } else if (type->t & VT_ARRAY) {
59835990 s = type->ref;
59845991 n = s->c;
@@ -6051,8 +6058,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 66 unmodified lines
60516058 }
60526059 } else {
60536060 index = 0;
6054− while (tok != '}') {
6055− decl_designator(type, sec, c, &index, NULL, size_only);
6061+ while (tok != '}' || have_elem) {
6062+ decl_designator(type, sec, c, &index, NULL, size_only, have_elem);
6063+ have_elem = 0;
60566064 if (n >= 0 && index >= n)
60576065 tcc_error("index too large");
60586066 /* must put zero in holes (note that doing it that way
@@ -6084,6 +6092,11 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 25 unmodified lines
60846092 /* patch type size if needed */
60856093 if (n < 0)
60866094 s->c = array_length;
6095+ } else if (1 && have_elem && is_compatible_types(type, &vtop->type)) {
6096+ /* currently, we always use constant expression for globals
6097+ (may change for scripting case) */
6098+ expr_type = !sec ? EXPR_ANY : EXPR_CONST;
6099+ init_putv(type, sec, c, 0, expr_type);
60876100 } else if ((type->t & VT_BTYPE) == VT_STRUCT &&
60886101 (!first || tok == '{')) {
60896102
@@ -6140,8 +6153,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 50 unmodified lines
61406153 array_length = 0;
61416154 index = 0;
61426155 n = s->c;
6143− while (tok != '}') {
6144− decl_designator(type, sec, c, NULL, &f, size_only);
6156+ while (tok != '}' || have_elem) {
6157+ decl_designator(type, sec, c, NULL, &f, size_only, have_elem);
6158+ have_elem = 0;
61456159 index = f->c;
61466160 if (!size_only && array_length < index) {
61476161 init_putz(type, sec, c + array_length,
@@ -6208,7 +6222,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 60 unmodified lines
62086222 }
62096223 } else if (tok == '{') {
62106224 next();
6211− decl_initializer(type, sec, c, first, size_only);
6225+ if (have_elem)
6226+ tcc_error("shouldn't have parsed init element");
6227+ decl_initializer(type, sec, c, first, size_only, 0);
62126228 skip('}');
62136229 } else if (size_only) {
62146230 /* just skip expression */
@@ -6232,12 +6248,16 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 17 unmodified lines
62326248 next();
62336249 }
62346250 } else {
6251+ if (!have_elem) {
6252+ /* This should happen only when we haven't parsed
6253+ the init element above for fear of committing a
6254+ string constant to memory too early. */
6255+ if (tok != TOK_STR && tok != TOK_LSTR)
6256+ expect("string constant");
6257+ parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
6258+ }
62356259 /* currently, we always use constant expression for globals
62366260 (may change for scripting case) */
6237− expr_type = EXPR_CONST;
6238− if (!sec)
6239− expr_type = EXPR_ANY;
6240− parse_init_elem(expr_type);
62416261 init_putv(type, sec, c, 0, expr_type);
62426262 }
62436263 }
@@ -6314,7 +6334,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 70 unmodified lines
63146334
63156335 begin_macro(init_str, 1);
63166336 next();
6317− decl_initializer(type, NULL, 0, 1, 1);
6337+ decl_initializer(type, NULL, 0, 1, 1, 0);
63186338 /* prepare second initializer parsing */
63196339 macro_ptr = init_str->str;
63206340 next();
@@ -6473,7 +6493,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 152 unmodified lines
64736493 #endif
64746494 }
64756495 if (has_init || (type->t & VT_VLA)) {
6476− decl_initializer(type, sec, addr, 1, 0);
6496+ decl_initializer(type, sec, addr, 1, 0, 0);
64776497 /* patch flexible array member size back to -1, */
64786498 /* for possible subsequent similar declarations */
64796499 if (flexible_array)
tests/tests2/86-struct-init.c+139−0
@@ -0,0 +1,139 @@
1+typedef unsigned char u8;
2+typedef struct {} empty_s;
3+struct contains_empty {
4+ u8 a;
5+ empty_s empty;
6+ u8 b;
7+};
8+struct contains_empty ce = { { (1) }, (empty_s){}, 022, };
9+/* The following decl of 'q' would demonstrate the TCC bug in init_putv when
10+ handling copying compound literals. (Compound literals
11+ aren't acceptable constant initializers in isoc99, but
12+ we accept them like gcc, except for this case)
13+//char *q = (char *){ "trara" }; */
14+struct SS {u8 a[3], b; };
15+struct SS sinit16[] = { { 1 }, 2 };
16+struct S
17+{
18+ u8 a,b;
19+ u8 c[2];
20+};
21+
22+struct T
23+{
24+ u8 s[16];
25+ u8 a;
26+};
27+
28+struct U
29+{
30+ u8 a;
31+ struct S s;
32+ u8 b;
33+ struct T t;
34+};
35+
36+struct V
37+{
38+ struct S s;
39+ struct T t;
40+ u8 a;
41+};
42+
43+struct W
44+{
45+ struct V t;
46+ struct S s[];
47+};
48+
49+struct S gs = ((struct S){1, 2, 3, 4});
50+struct S gs2 = {1, 2, {3, 4}};
51+struct T gt = {"hello", 42};
52+struct U gu = {3, 5,6,7,8, 4, "huhu", 43};
53+struct U gu2 = {3, {5,6,7,8}, 4, {"huhu", 43}};
54+/* Optional braces around scalar initializers. Accepted, but with
55+ a warning. */
56+struct U gu3 = { {3}, {5,6,7,8,}, 4, {"huhu", 43}};
57+/* Many superfluous braces and leaving out one initializer for U.s.c[1] */
58+struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} };
59+/* Superfluous braces and useless parens around values */
60+struct S gs3 = { (1), {(2)}, {(((3))), {4}}};
61+/* Superfluous braces, and leaving out braces for V.t, plus cast */
62+struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46};
63+/* Compund literal */
64+struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48};
65+/* Parens around compound literal */
66+struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50};
67+/* Initialization of a flex array member (warns in GCC) */
68+struct W gw = {{1,2,3,4}, {1,2,3,4,5}};
69+
70+#include <stdio.h>
71+void print_ (const char *name, const u8 *p, long size)
72+{
73+ printf ("%s:", name);
74+ while (size--) {
75+ printf (" %x", *p++);
76+ }
77+ printf ("\n");
78+}
79+#define print(x) print_(#x, (u8*)&x, sizeof (x))
80+#if 1
81+void foo (struct W *w)
82+{
83+ struct S ls = {1, 2, 3, 4};
84+ struct S ls2 = {1, 2, {3, 4}};
85+ struct T lt = {"hello", 42};
86+ struct U lu = {3, 5,6,7,8, 4, "huhu", 43};
87+ struct U lu1 = {3, ls, 4, {"huhu", 43}};
88+ struct U lu2 = {3, (ls), 4, {"huhu", 43}};
89+ /* Incomplete bracing. */
90+ struct U lu21 = {3, ls, 4, "huhu", 43};
91+ /* Optional braces around scalar initializers. Accepted, but with
92+ a warning. */
93+ struct U lu3 = { 3, {5,6,7,8,}, 4, {"huhu", 43}};
94+ /* Many superfluous braces and leaving out one initializer for U.s.c[1] */
95+ struct U lu4 = { 3, {5,6,7,}, 5, { "bla", 44} };
96+ /* Superfluous braces and useless parens around values */
97+ struct S ls3 = { (1), (2), {(((3))), 4}};
98+ /* Superfluous braces, and leaving out braces for V.t, plus cast */
99+ struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46};
100+ /* Compund literal */
101+ struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48};
102+ /* Parens around compound literal */
103+ struct V lv3 = {((struct S){7,8,{9,10}}), w->t.t, 50};
104+ print(ls);
105+ print(ls2);
106+ print(lt);
107+ print(lu);
108+ print(lu1);
109+ print(lu2);
110+ print(lu21);
111+ print(lu3);
112+ print(lu4);
113+ print(ls3);
114+ print(lv);
115+ print(lv2);
116+ print(lv3);
117+}
118+#endif
119+
120+int main()
121+{
122+ print(ce);
123+ print(gs);
124+ print(gs2);
125+ print(gt);
126+ print(gu);
127+ print(gu2);
128+ print(gu3);
129+ print(gu4);
130+ print(gs3);
131+ print(gv);
132+ print(gv2);
133+ print(gv3);
134+ print(sinit16);
135+ print(gw);
136+ foo(&gw);
137+ //printf("q: %s\n", q);
138+ return 0;
139+}
tests/tests2/86-struct-init.expect+27−0
@@ -0,0 +1,27 @@
1+ce: 1 12
2+gs: 1 2 3 4
3+gs2: 1 2 3 4
4+gt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
5+gu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
6+gu2: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
7+gu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
8+gu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c
9+gs3: 1 2 3 4
10+gv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
11+gv2: 7 8 9 a 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
12+gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32
13+sinit16: 1 0 0 0 2 0 0 0
14+gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
15+ls: 1 2 3 4
16+ls2: 1 2 3 4
17+lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
18+lu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
19+lu1: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
20+lu2: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
21+lu21: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
22+lu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
23+lu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c
24+ls3: 1 2 3 4
25+lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
26+lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
27+lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32
tests/tests2/Makefile+1−1
@@ -54,7 +54,7 @@ all test: $(filter-out $(SKIP),$(TESTS)) · 53 unmodified lines
5454
5555 # automatically generate .expect files with gcc:
5656 %.expect :
57− (gcc $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe
57+ (gcc -w $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe
5858
5959 # tell make not to delete
6060 .PRECIOUS: %.expect

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t