| @@ -78,6 +78,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re · 77 unmodified lines |
| 78 | 78 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); |
| 79 | 79 | static void expr_eq(void); |
| 80 | 80 | static void unary_type(CType *type); |
| 81 | +static void vla_runtime_type_size(CType *type, int *a); |
| 81 | 82 | static int is_compatible_parameter_types(CType *type1, CType *type2); |
| 82 | 83 | static void expr_type(CType *type); |
| 83 | 84 | |
| @@ -1455,6 +1456,12 @@ static int pointed_size(CType *type) · 1371 unmodified lines |
| 1455 | 1456 | return type_size(pointed_type(type), &align); |
| 1456 | 1457 | } |
| 1457 | 1458 | |
| 1459 | +static void vla_runtime_pointed_size(CType *type) |
| 1460 | +{ |
| 1461 | + int align; |
| 1462 | + vla_runtime_type_size(pointed_type(type), &align); |
| 1463 | +} |
| 1464 | + |
| 1458 | 1465 | static inline int is_null_pointer(SValue *p) |
| 1459 | 1466 | { |
| 1460 | 1467 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
| @@ -1543,11 +1550,20 @@ ST_FUNC void gen_op(int op) · 82 unmodified lines |
| 1543 | 1550 | } |
| 1544 | 1551 | /* if both pointers, then it must be the '-' op */ |
| 1545 | 1552 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
| 1553 | + int ptr1_is_vla; |
| 1554 | + |
| 1555 | + ptr1_is_vla = 0; |
| 1546 | 1556 | if (op != '-') |
| 1547 | 1557 | error("cannot use pointers here"); |
| 1548 | 1558 | check_comparison_pointer_types(vtop - 1, vtop, op); |
| 1549 | 1559 | /* XXX: check that types are compatible */ |
| 1550 | | − u = pointed_size(&vtop[-1].type); |
| 1560 | + if (vtop[-1].type.t & VT_VLA) { |
| 1561 | + vla_runtime_pointed_size(&vtop[-1].type); |
| 1562 | + vrott(3); |
| 1563 | + ptr1_is_vla = 1; |
| 1564 | + } else { |
| 1565 | + u = pointed_size(&vtop[-1].type); |
| 1566 | + } |
| 1551 | 1567 | gen_opic(op); |
| 1552 | 1568 | /* set to integer type */ |
| 1553 | 1569 | #ifdef TCC_TARGET_X86_64 |
| @@ -1555,7 +1571,10 @@ ST_FUNC void gen_op(int op) · 1 unmodified line |
| 1555 | 1571 | #else |
| 1556 | 1572 | vtop->type.t = VT_INT; |
| 1557 | 1573 | #endif |
| 1558 | | − vpushi(u); |
| 1574 | + if (ptr1_is_vla) |
| 1575 | + vswap(); |
| 1576 | + else |
| 1577 | + vpushi(u); |
| 1559 | 1578 | gen_op(TOK_PDIV); |
| 1560 | 1579 | } else { |
| 1561 | 1580 | /* exactly one pointer : must be '+' or '-'. */ |
| @@ -1567,16 +1586,20 @@ ST_FUNC void gen_op(int op) · 5 unmodified lines |
| 1567 | 1586 | swap(&t1, &t2); |
| 1568 | 1587 | } |
| 1569 | 1588 | type1 = vtop[-1].type; |
| 1570 | | − type1.t &= ~VT_ARRAY; |
| 1571 | | − u = pointed_size(&vtop[-1].type); |
| 1572 | | − if (u < 0) |
| 1573 | | − error("unknown array element size"); |
| 1589 | + type1.t &= ~(VT_ARRAY|VT_VLA); |
| 1590 | + if (vtop[-1].type.t & VT_VLA) |
| 1591 | + vla_runtime_pointed_size(&vtop[-1].type); |
| 1592 | + else { |
| 1593 | + u = pointed_size(&vtop[-1].type); |
| 1594 | + if (u < 0) |
| 1595 | + error("unknown array element size"); |
| 1574 | 1596 | #ifdef TCC_TARGET_X86_64 |
| 1575 | | − vpushll(u); |
| 1597 | + vpushll(u); |
| 1576 | 1598 | #else |
| 1577 | | − /* XXX: cast to int ? (long long case) */ |
| 1578 | | − vpushi(u); |
| 1599 | + /* XXX: cast to int ? (long long case) */ |
| 1600 | + vpushi(u); |
| 1579 | 1601 | #endif |
| 1602 | + } |
| 1580 | 1603 | gen_op('*'); |
| 1581 | 1604 | #ifdef CONFIG_TCC_BCHECK |
| 1582 | 1605 | /* if evaluating constant expression, no code should be |
| @@ -1932,7 +1955,7 @@ static void gen_cast(CType *type) · 349 unmodified lines |
| 1932 | 1955 | vtop->type = *type; |
| 1933 | 1956 | } |
| 1934 | 1957 | |
| 1935 | | −/* return type size. Put alignment at 'a' */ |
| 1958 | +/* return type size as known at compile time. Put alignment at 'a' */ |
| 1936 | 1959 | ST_FUNC int type_size(CType *type, int *a) |
| 1937 | 1960 | { |
| 1938 | 1961 | Sym *s; |
| @@ -1945,7 +1968,10 @@ ST_FUNC int type_size(CType *type, int *a) · 6 unmodified lines |
| 1945 | 1968 | *a = s->r; |
| 1946 | 1969 | return s->c; |
| 1947 | 1970 | } else if (bt == VT_PTR) { |
| 1948 | | − if (type->t & VT_ARRAY) { |
| 1971 | + if (type->t & VT_VLA) { |
| 1972 | + *a = 1; |
| 1973 | + return 0; |
| 1974 | + } else if (type->t & VT_ARRAY) { |
| 1949 | 1975 | int ts; |
| 1950 | 1976 | |
| 1951 | 1977 | s = type->ref; |
| @@ -1992,6 +2018,30 @@ ST_FUNC int type_size(CType *type, int *a) · 40 unmodified lines |
| 1992 | 2018 | } |
| 1993 | 2019 | } |
| 1994 | 2020 | |
| 2021 | +/* push type size as known at runtime time on top of value stack. Put |
| 2022 | + alignment at 'a' */ |
| 2023 | +ST_FUNC void vla_runtime_type_size(CType *type, int *a) |
| 2024 | +{ |
| 2025 | + if (type->t & VT_VLA) { |
| 2026 | + Sym *s; |
| 2027 | + |
| 2028 | + s = type->ref; |
| 2029 | + vla_runtime_type_size(&s->type, a); |
| 2030 | + vpushv(s->s); |
| 2031 | + if ((vtop->r & (VT_SYM|VT_LVAL|VT_VALMASK)) != VT_CONST) { |
| 2032 | + gv_dup(); |
| 2033 | + vswap(); |
| 2034 | + vpop(); |
| 2035 | + } |
| 2036 | + gen_op('*'); |
| 2037 | + } else { |
| 2038 | + int size; |
| 2039 | + |
| 2040 | + size = type_size(type, a); |
| 2041 | + vpushi(size); |
| 2042 | + } |
| 2043 | +} |
| 2044 | + |
| 1995 | 2045 | /* return the pointed type of t */ |
| 1996 | 2046 | static inline CType *pointed_type(CType *type) |
| 1997 | 2047 | { |
| @@ -3103,25 +3153,43 @@ static void post_type(CType *type, AttributeDef *ad) · 1105 unmodified lines |
| 3103 | 3153 | type->t = t1 | VT_FUNC; |
| 3104 | 3154 | type->ref = s; |
| 3105 | 3155 | } else if (tok == '[') { |
| 3156 | + SValue *last_vtop = NULL; |
| 3157 | + |
| 3106 | 3158 | /* array definition */ |
| 3107 | 3159 | next(); |
| 3108 | 3160 | if (tok == TOK_RESTRICT1) |
| 3109 | 3161 | next(); |
| 3110 | 3162 | n = -1; |
| 3111 | 3163 | if (tok != ']') { |
| 3112 | | − n = expr_const(); |
| 3113 | | − if (n < 0) |
| 3114 | | − error("invalid array size"); |
| 3164 | + gexpr(); |
| 3165 | + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
| 3166 | + n = vtop->c.i; |
| 3167 | + last_vtop = vtop; |
| 3168 | + if (n < 0) |
| 3169 | + error("invalid array size"); |
| 3170 | + } else { |
| 3171 | + if (!is_integer_btype(vtop->type.t & VT_BTYPE)) |
| 3172 | + error("size of variable length array should be an integer"); |
| 3173 | + type->t |= VT_VLA; |
| 3174 | + last_vtop = vtop; |
| 3175 | + } |
| 3115 | 3176 | } |
| 3116 | 3177 | skip(']'); |
| 3117 | 3178 | /* parse next post type */ |
| 3118 | | − t1 = type->t & VT_STORAGE; |
| 3119 | | − type->t &= ~VT_STORAGE; |
| 3179 | + t1 = type->t & (VT_STORAGE|VT_VLA); |
| 3180 | + type->t &= ~(VT_STORAGE|VT_VLA); |
| 3120 | 3181 | post_type(type, ad); |
| 3182 | + t1 |= type->t & VT_VLA; |
| 3121 | 3183 | |
| 3122 | | − /* we push a anonymous symbol which will contain the array |
| 3184 | + /* we push an anonymous symbol which will contain the array |
| 3123 | 3185 | element type */ |
| 3124 | 3186 | s = sym_push(SYM_FIELD, type, 0, n); |
| 3187 | + if (t1 & VT_VLA) { |
| 3188 | + s->s = last_vtop; // That's ok, we don't need n with VLA |
| 3189 | + } else { |
| 3190 | + if (n >= 0) |
| 3191 | + vpop(); |
| 3192 | + } |
| 3125 | 3193 | type->t = t1 | VT_ARRAY | VT_PTR; |
| 3126 | 3194 | type->ref = s; |
| 3127 | 3195 | } |
| @@ -3490,11 +3558,18 @@ ST_FUNC void unary(void) · 362 unmodified lines |
| 3490 | 3558 | next(); |
| 3491 | 3559 | in_sizeof++; |
| 3492 | 3560 | unary_type(&type); // Perform a in_sizeof = 0; |
| 3493 | | − size = type_size(&type, &align); |
| 3561 | + if ((t == TOK_SIZEOF) && (type.t & VT_VLA)) { |
| 3562 | + vla_runtime_type_size(&type, &align); |
| 3563 | + size = 0; |
| 3564 | + } else { |
| 3565 | + size = type_size(&type, &align); |
| 3566 | + } |
| 3494 | 3567 | if (t == TOK_SIZEOF) { |
| 3495 | | − if (size < 0) |
| 3496 | | − error("sizeof applied to an incomplete type"); |
| 3497 | | − vpushi(size); |
| 3568 | + if (!(type.t & VT_VLA)) { |
| 3569 | + if (size < 0) |
| 3570 | + error("sizeof applied to an incomplete type"); |
| 3571 | + vpushi(size); |
| 3572 | + } |
| 3498 | 3573 | } else { |
| 3499 | 3574 | vpushi(align); |
| 3500 | 3575 | } |
| @@ -3653,7 +3728,10 @@ ST_FUNC void unary(void) · 152 unmodified lines |
| 3653 | 3728 | } else { |
| 3654 | 3729 | r = s->r; |
| 3655 | 3730 | } |
| 3656 | | − vset(&s->type, r, s->c); |
| 3731 | + if (s->type.t & VT_VLA) |
| 3732 | + vpushv(s->s); |
| 3733 | + else |
| 3734 | + vset(&s->type, r, s->c); |
| 3657 | 3735 | /* if forward reference, we must point to s */ |
| 3658 | 3736 | if (vtop->r & VT_SYM) { |
| 3659 | 3737 | vtop->sym = s; |
| @@ -4782,7 +4860,18 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 1122 unmodified lines |
| 4782 | 4860 | Sym *s, *f; |
| 4783 | 4861 | CType *t1; |
| 4784 | 4862 | |
| 4785 | | − if (type->t & VT_ARRAY) { |
| 4863 | + if (type->t & VT_VLA) { |
| 4864 | + int a; |
| 4865 | + CValue retcval; |
| 4866 | + |
| 4867 | + vpush_global_sym(&func_old_type, TOK_alloca); |
| 4868 | + vla_runtime_type_size(type, &a); |
| 4869 | + gfunc_call(1); |
| 4870 | + |
| 4871 | + /* return value */ |
| 4872 | + retcval.i = 0; |
| 4873 | + vsetc(type, REG_IRET, &retcval); |
| 4874 | + } else if (type->t & VT_ARRAY) { |
| 4786 | 4875 | s = type->ref; |
| 4787 | 4876 | n = s->c; |
| 4788 | 4877 | array_length = 0; |
| @@ -5013,6 +5102,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 224 unmodified lines |
| 5013 | 5102 | ParseState saved_parse_state = {0}; |
| 5014 | 5103 | TokenString init_str; |
| 5015 | 5104 | Section *sec; |
| 5105 | + Sym *vla = NULL; |
| 5016 | 5106 | |
| 5017 | 5107 | size = type_size(type, &align); |
| 5018 | 5108 | /* If unknown size, we must evaluate it before |
| @@ -5078,8 +5168,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 59 unmodified lines |
| 5078 | 5168 | if ((r & VT_VALMASK) == VT_LOCAL) { |
| 5079 | 5169 | sec = NULL; |
| 5080 | 5170 | #ifdef CONFIG_TCC_BCHECK |
| 5081 | | − if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) |
| 5082 | | − loc--; |
| 5171 | + if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { |
| 5172 | + if (type->t & VT_VLA) |
| 5173 | + warning("Array bound check don't work for VLA"); |
| 5174 | + else |
| 5175 | + loc--; |
| 5176 | + } |
| 5083 | 5177 | #endif |
| 5084 | 5178 | loc = (loc - size) & -align; |
| 5085 | 5179 | addr = loc; |
| @@ -5087,7 +5181,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1 unmodified line |
| 5087 | 5181 | /* handles bounds */ |
| 5088 | 5182 | /* XXX: currently, since we do only one pass, we cannot track |
| 5089 | 5183 | '&' operators, so we add only arrays */ |
| 5090 | | − if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { |
| 5184 | + if (tcc_state->do_bounds_check && (type->t & VT_ARRAY) && |
| 5185 | + !(type->t & VT_VLA)) { |
| 5091 | 5186 | unsigned long *bounds_ptr; |
| 5092 | 5187 | /* add padding between regions */ |
| 5093 | 5188 | loc--; |
| @@ -5099,7 +5194,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 5 unmodified lines |
| 5099 | 5194 | #endif |
| 5100 | 5195 | if (v) { |
| 5101 | 5196 | /* local variable */ |
| 5102 | | − sym_push(v, type, r, addr); |
| 5197 | + vla = sym_push(v, type, r, addr); |
| 5103 | 5198 | } else { |
| 5104 | 5199 | /* push local reference */ |
| 5105 | 5200 | vset(type, r, addr); |
| @@ -5214,8 +5309,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 108 unmodified lines |
| 5214 | 5309 | } |
| 5215 | 5310 | #endif |
| 5216 | 5311 | } |
| 5217 | | − if (has_init) { |
| 5312 | + if (has_init || (type->t & VT_VLA)) { |
| 5218 | 5313 | decl_initializer(type, sec, addr, 1, 0); |
| 5314 | + if (type->t & VT_VLA) |
| 5315 | + vla->s = vtop; |
| 5219 | 5316 | /* restore parse state if needed */ |
| 5220 | 5317 | if (init_str.str) { |
| 5221 | 5318 | tok_str_free(init_str.str); |
| @@ -5584,9 +5681,12 @@ ST_FUNC void decl(int l) · 362 unmodified lines |
| 5584 | 5681 | if (!(type.t & VT_ARRAY)) |
| 5585 | 5682 | r |= lvalue_type(type.t); |
| 5586 | 5683 | has_init = (tok == '='); |
| 5684 | + if (has_init && (type.t & VT_VLA)) |
| 5685 | + error("Variable length array cannot be initialized"); |
| 5587 | 5686 | if ((btype.t & VT_EXTERN) || |
| 5588 | | − ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
| 5589 | | − !has_init && l == VT_CONST && type.ref->c < 0)) { |
| 5687 | + ((type.t & VT_ARRAY) && (!(type.t & VT_VLA)) && |
| 5688 | + (type.t & VT_STATIC) && !has_init && l == VT_CONST && |
| 5689 | + type.ref->c < 0)) { |
| 5590 | 5690 | /* external variable */ |
| 5591 | 5691 | /* NOTE: as GCC, uninitialized global static |
| 5592 | 5692 | arrays of null size are considered as |