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
74static int parse_btype(CType *type, AttributeDef *ad);74static int parse_btype(CType *type, AttributeDef *ad);
75static void type_decl(CType *type, AttributeDef *ad, int *v, int td);75static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
76static void parse_expr_type(CType *type);76static void parse_expr_type(CType *type);
77static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);77static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only, int have_elem);
78static void block(int *bsym, int *csym, int is_expr);78static void block(int *bsym, int *csym, int is_expr);
79static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);79static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
80static int decl0(int l, int is_for_loop_init);80static 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
5650 }5650 }
5651}5651}
5652 5652
5653#define EXPR_VAL 0
5654#define EXPR_CONST 1
5655#define EXPR_ANY 2
5656
5657static 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
5653/* t is the array or struct type. c is the array or struct5677/* t is the array or struct type. c is the array or struct
5654 address. cur_index/cur_field is the pointer to the current5678 address. cur_index/cur_field is the pointer to the current
5655 value. 'size_only' is true if only size info is needed (only used5679 value. 'size_only' is true if only size info is needed (only used
5656 in arrays) */5680 in arrays) */
5657static void decl_designator(CType *type, Section *sec, unsigned long c, 5681static void decl_designator(CType *type, Section *sec, unsigned long c,
5658 int *cur_index, Sym **cur_field, 5682 int *cur_index, Sym **cur_field,
5659 int size_only)5683 int size_only, int have_elem)
5660{5684{
5661 Sym *s, *f;5685 Sym *s, *f;
5662 int notfirst, index, index_last, align, l, nb_elems, elem_size;5686 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
5748 c += f->c;5772 c += f->c;
5749 }5773 }
5750 }5774 }
5751 decl_initializer(type, sec, c, 0, size_only);5775 decl_initializer(type, sec, c, 0, size_only, have_elem);
5752 5776
5753 /* XXX: make it more general */5777 /* XXX: make it more general */
5754 if (!size_only && nb_elems > 1) {5778 if (!size_only && nb_elems > 1) {
@@ -5770,30 +5794,6 @@ static void decl_designator(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
5770 }5794 }
5771}5795}
5772 5796
5773#define EXPR_VAL 0
5774#define EXPR_CONST 1
5775#define EXPR_ANY 2
5776
5777static 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
5797/* store a value or an expression directly in global data or in local array */5797/* store a value or an expression directly in global data or in local array */
5798static void init_putv(CType *type, Section *sec, unsigned long c,5798static void init_putv(CType *type, Section *sec, unsigned long c,
5799 int v, int expr_type)5799 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
5957 dimension implicit array init handling). 'size_only' is true if5957 dimension implicit array init handling). 'size_only' is true if
5958 size only evaluation is wanted (only for arrays). */5958 size only evaluation is wanted (only for arrays). */
5959static void decl_initializer(CType *type, Section *sec, unsigned long c, 5959static 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)
5961{5961{
5962 int index, array_length, n, no_oblock, nb, parlevel, parlevel1, i;5962 int index, array_length, n, no_oblock, nb, parlevel, parlevel1, i;
5963 int size1, align1, expr_type;5963 int size1, align1, expr_type;
@@ -5979,6 +5979,13 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
5979 gen_vla_sp_save(c);5979 gen_vla_sp_save(c);
5980 vla_sp_loc = c;5980 vla_sp_loc = c;
5981 vlas_in_scope++;5981 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) {
5982 } else if (type->t & VT_ARRAY) {5989 } else if (type->t & VT_ARRAY) {
5983 s = type->ref;5990 s = type->ref;
5984 n = s->c;5991 n = s->c;
@@ -6051,8 +6058,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 66 unmodified lines
6051 }6058 }
6052 } else {6059 } else {
6053 index = 0;6060 index = 0;
6054 while (tok != '}') {6061 while (tok != '}' || have_elem) {
6055 decl_designator(type, sec, c, &index, NULL, size_only);6062 decl_designator(type, sec, c, &index, NULL, size_only, have_elem);
6063 have_elem = 0;
6056 if (n >= 0 && index >= n)6064 if (n >= 0 && index >= n)
6057 tcc_error("index too large");6065 tcc_error("index too large");
6058 /* must put zero in holes (note that doing it that way6066 /* 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
6084 /* patch type size if needed */6092 /* patch type size if needed */
6085 if (n < 0)6093 if (n < 0)
6086 s->c = array_length;6094 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);
6087 } else if ((type->t & VT_BTYPE) == VT_STRUCT &&6100 } else if ((type->t & VT_BTYPE) == VT_STRUCT &&
6088 (!first || tok == '{')) {6101 (!first || tok == '{')) {
6089 6102
@@ -6140,8 +6153,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 50 unmodified lines
6140 array_length = 0;6153 array_length = 0;
6141 index = 0;6154 index = 0;
6142 n = s->c;6155 n = s->c;
6143 while (tok != '}') {6156 while (tok != '}' || have_elem) {
6144 decl_designator(type, sec, c, NULL, &f, size_only);6157 decl_designator(type, sec, c, NULL, &f, size_only, have_elem);
6158 have_elem = 0;
6145 index = f->c;6159 index = f->c;
6146 if (!size_only && array_length < index) {6160 if (!size_only && array_length < index) {
6147 init_putz(type, sec, c + array_length, 6161 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
6208 }6222 }
6209 } else if (tok == '{') {6223 } else if (tok == '{') {
6210 next();6224 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);
6212 skip('}');6228 skip('}');
6213 } else if (size_only) {6229 } else if (size_only) {
6214 /* just skip expression */6230 /* just skip expression */
@@ -6232,12 +6248,16 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 17 unmodified lines
6232 next();6248 next();
6233 }6249 }
6234 } else {6250 } 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 }
6235 /* currently, we always use constant expression for globals6259 /* currently, we always use constant expression for globals
6236 (may change for scripting case) */6260 (may change for scripting case) */
6237 expr_type = EXPR_CONST;
6238 if (!sec)
6239 expr_type = EXPR_ANY;
6240 parse_init_elem(expr_type);
6241 init_putv(type, sec, c, 0, expr_type);6261 init_putv(type, sec, c, 0, expr_type);
6242 }6262 }
6243}6263}
@@ -6314,7 +6334,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 70 unmodified lines
6314 6334
6315 begin_macro(init_str, 1);6335 begin_macro(init_str, 1);
6316 next();6336 next();
6317 decl_initializer(type, NULL, 0, 1, 1);6337 decl_initializer(type, NULL, 0, 1, 1, 0);
6318 /* prepare second initializer parsing */6338 /* prepare second initializer parsing */
6319 macro_ptr = init_str->str;6339 macro_ptr = init_str->str;
6320 next();6340 next();
@@ -6473,7 +6493,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 152 unmodified lines
6473#endif6493#endif
6474 }6494 }
6475 if (has_init || (type->t & VT_VLA)) {6495 if (has_init || (type->t & VT_VLA)) {
6476 decl_initializer(type, sec, addr, 1, 0);6496 decl_initializer(type, sec, addr, 1, 0, 0);
6477 /* patch flexible array member size back to -1, */6497 /* patch flexible array member size back to -1, */
6478 /* for possible subsequent similar declarations */6498 /* for possible subsequent similar declarations */
6479 if (flexible_array)6499 if (flexible_array)
tests/tests2/86-struct-init.c+139−0
@@ -0,0 +1,139 @@
1typedef unsigned char u8;
2typedef struct {} empty_s;
3struct contains_empty {
4 u8 a;
5 empty_s empty;
6 u8 b;
7};
8struct 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" }; */
14struct SS {u8 a[3], b; };
15struct SS sinit16[] = { { 1 }, 2 };
16struct S
17{
18 u8 a,b;
19 u8 c[2];
20};
21
22struct T
23{
24 u8 s[16];
25 u8 a;
26};
27
28struct U
29{
30 u8 a;
31 struct S s;
32 u8 b;
33 struct T t;
34};
35
36struct V
37{
38 struct S s;
39 struct T t;
40 u8 a;
41};
42
43struct W
44{
45 struct V t;
46 struct S s[];
47};
48
49struct S gs = ((struct S){1, 2, 3, 4});
50struct S gs2 = {1, 2, {3, 4}};
51struct T gt = {"hello", 42};
52struct U gu = {3, 5,6,7,8, 4, "huhu", 43};
53struct U gu2 = {3, {5,6,7,8}, 4, {"huhu", 43}};
54/* Optional braces around scalar initializers. Accepted, but with
55 a warning. */
56struct U gu3 = { {3}, {5,6,7,8,}, 4, {"huhu", 43}};
57/* Many superfluous braces and leaving out one initializer for U.s.c[1] */
58struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} };
59/* Superfluous braces and useless parens around values */
60struct S gs3 = { (1), {(2)}, {(((3))), {4}}};
61/* Superfluous braces, and leaving out braces for V.t, plus cast */
62struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46};
63/* Compund literal */
64struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48};
65/* Parens around compound literal */
66struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50};
67/* Initialization of a flex array member (warns in GCC) */
68struct W gw = {{1,2,3,4}, {1,2,3,4,5}};
69
70#include <stdio.h>
71void 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
81void 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
120int 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 @@
1ce: 1 12
2gs: 1 2 3 4
3gs2: 1 2 3 4
4gt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
5gu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
6gu2: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
7gu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
8gu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c
9gs3: 1 2 3 4
10gv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
11gv2: 7 8 9 a 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
12gv3: 7 8 9 a 68 6f 68 6f 0 0 0 0 0 0 0 0 0 0 0 0 31 32
13sinit16: 1 0 0 0 2 0 0 0
14gw: 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
15ls: 1 2 3 4
16ls2: 1 2 3 4
17lt: 68 65 6c 6c 6f 0 0 0 0 0 0 0 0 0 0 0 2a
18lu: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
19lu1: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
20lu2: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
21lu21: 3 1 2 3 4 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
22lu3: 3 5 6 7 8 4 68 75 68 75 0 0 0 0 0 0 0 0 0 0 0 0 2b
23lu4: 3 5 6 7 0 5 62 6c 61 0 0 0 0 0 0 0 0 0 0 0 0 0 2c
24ls3: 1 2 3 4
25lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
26lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
27lv3: 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
54 54
55# automatically generate .expect files with gcc:55# automatically generate .expect files with gcc:
56%.expect :56%.expect :
57 (gcc $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe57 (gcc -w $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe
58 58
59# tell make not to delete59# tell make not to delete
60.PRECIOUS: %.expect60.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