Fix some string literal expressions in initializers
Things like 'char x[] = { "foo"[1], 0 }' (which should initialize
a two-character array 'x' with "o\0").  See added testcase.
			
			
This commit is contained in:
		
							parent
							
								
									b2d351e0ec
								
							
						
					
					
						commit
						7b6931ed1f
					
				
					 3 changed files with 97 additions and 37 deletions
				
			
		
							
								
								
									
										2
									
								
								tcc.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								tcc.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -449,8 +449,8 @@ typedef union CValue {
 | 
			
		|||
    float f;
 | 
			
		||||
    uint64_t i;
 | 
			
		||||
    struct {
 | 
			
		||||
        int size;
 | 
			
		||||
        const void *data;
 | 
			
		||||
        int size;
 | 
			
		||||
    } str;
 | 
			
		||||
    int tab[LDOUBLE_SIZE/4];
 | 
			
		||||
} CValue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								tccgen.c
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								tccgen.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -81,6 +81,7 @@ ST_DATA int func_vc;
 | 
			
		|||
static int last_line_num, new_file, func_ind; /* debug info control */
 | 
			
		||||
ST_DATA const char *funcname;
 | 
			
		||||
ST_DATA CType int_type, func_old_type, char_pointer_type;
 | 
			
		||||
static CString initstr;
 | 
			
		||||
 | 
			
		||||
#if PTR_SIZE == 4
 | 
			
		||||
#define VT_SIZE_T (VT_INT | VT_UNSIGNED)
 | 
			
		||||
| 
						 | 
				
			
			@ -779,6 +780,7 @@ ST_FUNC void tccgen_init(TCCState *s1)
 | 
			
		|||
#ifdef precedence_parser
 | 
			
		||||
    init_prec();
 | 
			
		||||
#endif
 | 
			
		||||
    cstr_new(&initstr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ST_FUNC int tccgen_compile(TCCState *s1)
 | 
			
		||||
| 
						 | 
				
			
			@ -810,6 +812,7 @@ ST_FUNC int tccgen_compile(TCCState *s1)
 | 
			
		|||
 | 
			
		||||
ST_FUNC void tccgen_finish(TCCState *s1)
 | 
			
		||||
{
 | 
			
		||||
    cstr_free(&initstr);
 | 
			
		||||
    free_inline_functions(s1);
 | 
			
		||||
    sym_pop(&global_stack, NULL, 0);
 | 
			
		||||
    sym_pop(&local_stack, NULL, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -3219,7 +3222,6 @@ redo:
 | 
			
		|||
                gen_cast_s(VT_INT);
 | 
			
		||||
#endif
 | 
			
		||||
            type1 = vtop[-1].type;
 | 
			
		||||
            type1.t &= ~VT_ARRAY;
 | 
			
		||||
            if (vtop[-1].type.t & VT_VLA)
 | 
			
		||||
                vla_runtime_pointed_size(&vtop[-1].type);
 | 
			
		||||
            else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3249,6 +3251,7 @@ redo:
 | 
			
		|||
            {
 | 
			
		||||
                gen_opic(op);
 | 
			
		||||
            }
 | 
			
		||||
            type1.t &= ~VT_ARRAY;
 | 
			
		||||
            /* put again type if gen_opic() swaped operands */
 | 
			
		||||
            vtop->type = type1;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -7442,7 +7445,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
 | 
			
		|||
	       anonymous one.  That is, there's no difference in vtop
 | 
			
		||||
	       between '(void *){x}' and '&(void *){x}'.  Ignore
 | 
			
		||||
	       pointer typed entities here.  Hopefully no real code
 | 
			
		||||
	       will every use compound literals with scalar type.  */
 | 
			
		||||
	       will ever use compound literals with scalar type.  */
 | 
			
		||||
	    (vtop->type.t & VT_BTYPE) != VT_PTR) {
 | 
			
		||||
	    /* These come from compound literals, memcpy stuff over.  */
 | 
			
		||||
	    Section *ssec;
 | 
			
		||||
| 
						 | 
				
			
			@ -7450,7 +7453,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
 | 
			
		|||
	    ElfW_Rel *rel;
 | 
			
		||||
	    esym = elfsym(vtop->sym);
 | 
			
		||||
	    ssec = tcc_state->sections[esym->st_shndx];
 | 
			
		||||
	    memmove (ptr, ssec->data + esym->st_value, size);
 | 
			
		||||
	    memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size);
 | 
			
		||||
	    if (ssec->reloc) {
 | 
			
		||||
		/* We need to copy over all memory contents, and that
 | 
			
		||||
		   includes relocations.  Use the fact that relocs are
 | 
			
		||||
| 
						 | 
				
			
			@ -7593,7 +7596,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
 | 
			
		|||
static void decl_initializer(CType *type, Section *sec, unsigned long c, 
 | 
			
		||||
                             int flags)
 | 
			
		||||
{
 | 
			
		||||
    int len, n, no_oblock, nb, i;
 | 
			
		||||
    int len, n, no_oblock, i;
 | 
			
		||||
    int size1, align1;
 | 
			
		||||
    Sym *s, *f;
 | 
			
		||||
    Sym indexsym;
 | 
			
		||||
| 
						 | 
				
			
			@ -7641,42 +7644,55 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
 | 
			
		|||
             (t1->t & VT_BTYPE) == VT_INT
 | 
			
		||||
#endif
 | 
			
		||||
            ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
 | 
			
		||||
            int nb;
 | 
			
		||||
	    len = 0;
 | 
			
		||||
            cstr_reset(&initstr);
 | 
			
		||||
            if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
 | 
			
		||||
              tcc_error("unhandled string literal merging");
 | 
			
		||||
            while (tok == TOK_STR || tok == TOK_LSTR) {
 | 
			
		||||
                int cstr_len, ch;
 | 
			
		||||
 | 
			
		||||
                /* compute maximum number of chars wanted */
 | 
			
		||||
                if (initstr.size)
 | 
			
		||||
                  initstr.size -= size1;
 | 
			
		||||
                if (tok == TOK_STR)
 | 
			
		||||
                    cstr_len = tokc.str.size;
 | 
			
		||||
                  len += tokc.str.size;
 | 
			
		||||
                else
 | 
			
		||||
                    cstr_len = tokc.str.size / sizeof(nwchar_t);
 | 
			
		||||
                cstr_len--;
 | 
			
		||||
                nb = cstr_len;
 | 
			
		||||
                if (n >= 0 && nb > (n - len))
 | 
			
		||||
                    nb = n - len;
 | 
			
		||||
                  len += tokc.str.size / sizeof(nwchar_t);
 | 
			
		||||
                len--;
 | 
			
		||||
                cstr_cat(&initstr, tokc.str.data, tokc.str.size);
 | 
			
		||||
                next();
 | 
			
		||||
            }
 | 
			
		||||
            if (tok != ')' && tok != '}' && tok != ',' && tok != ';'
 | 
			
		||||
                && tok != TOK_EOF) {
 | 
			
		||||
                /* Not a lone literal but part of a bigger expression.  */
 | 
			
		||||
                unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
 | 
			
		||||
                tokc.str.size = initstr.size;
 | 
			
		||||
                tokc.str.data = initstr.data;
 | 
			
		||||
                indexsym.c = 0;
 | 
			
		||||
                f = &indexsym;
 | 
			
		||||
                goto do_init_list;
 | 
			
		||||
            }
 | 
			
		||||
            nb = len;
 | 
			
		||||
            if (n >= 0 && len > n)
 | 
			
		||||
              nb = n;
 | 
			
		||||
            if (!(flags & DIF_SIZE_ONLY)) {
 | 
			
		||||
                    if (cstr_len > nb)
 | 
			
		||||
                if (len > nb)
 | 
			
		||||
                  tcc_warning("initializer-string for array is too long");
 | 
			
		||||
                /* in order to go faster for common case (char
 | 
			
		||||
                   string in global variable, we handle it
 | 
			
		||||
                   specifically */
 | 
			
		||||
                    if (sec && tok == TOK_STR && size1 == 1) {
 | 
			
		||||
                if (sec && size1 == 1) {
 | 
			
		||||
                    if (!NODATA_WANTED)
 | 
			
		||||
                            memcpy(sec->data + c + len, tokc.str.data, nb);
 | 
			
		||||
                      memcpy(sec->data + c, initstr.data, nb);
 | 
			
		||||
                } else {
 | 
			
		||||
                    for(i=0;i<nb;i++) {
 | 
			
		||||
                            if (tok == TOK_STR)
 | 
			
		||||
                                ch = ((unsigned char *)tokc.str.data)[i];
 | 
			
		||||
                        if (size1 == 1)
 | 
			
		||||
                          ch = ((unsigned char *)initstr.data)[i];
 | 
			
		||||
                        else
 | 
			
		||||
                                ch = ((nwchar_t *)tokc.str.data)[i];
 | 
			
		||||
                          ch = ((nwchar_t *)initstr.data)[i];
 | 
			
		||||
                        vpushi(ch);
 | 
			
		||||
                            init_putv(t1, sec, c + (len + i) * size1);
 | 
			
		||||
                        init_putv(t1, sec, c + i * size1);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
                len += nb;
 | 
			
		||||
                next();
 | 
			
		||||
            }
 | 
			
		||||
            /* only add trailing zero if enough storage (no
 | 
			
		||||
               warning in this case since it is standard) */
 | 
			
		||||
            if (n < 0 || len < n) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -467,6 +467,48 @@ int ret(a)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char str_ag1[] = "b";
 | 
			
		||||
char str_ag2[] = { "b" };
 | 
			
		||||
/*char str_bg1[] = ("cccc"); GCC accepts this with pedantic warning, TCC not */
 | 
			
		||||
char str_ag3[] = { "ab"[1], 0 };
 | 
			
		||||
char str_ag4[2] = { "b" };
 | 
			
		||||
char str_x[2] = { "xy" "z"[2], 0 };
 | 
			
		||||
char *str_ar[] = { "one", "two" };
 | 
			
		||||
struct str_SS {unsigned char a[3], b; };
 | 
			
		||||
struct str_SS str_sinit15 = { "r" };
 | 
			
		||||
struct str_SS str_sinit16[] = { { "q" }, 2 };
 | 
			
		||||
 | 
			
		||||
static void string_test2()
 | 
			
		||||
{
 | 
			
		||||
    char *p = "hello";
 | 
			
		||||
    char a3[2] = { "p" };
 | 
			
		||||
    char a4[2] = { "ab" "c"[2], 0 };
 | 
			
		||||
    char *pa1 = "def" + 1;
 | 
			
		||||
    char *pa2 = { "xyz" + 1 };
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    struct str_SS ss = { { [0 ... 1] = 'a' }, 0 };
 | 
			
		||||
    puts("string_test2");
 | 
			
		||||
    puts(str_ag1);
 | 
			
		||||
    puts(str_ag2);
 | 
			
		||||
    /*puts(str_bg1);*/
 | 
			
		||||
    puts(str_ag3);
 | 
			
		||||
    puts(str_ag4);
 | 
			
		||||
    puts(str_x);
 | 
			
		||||
    puts(str_sinit15.a);
 | 
			
		||||
    puts(str_sinit16[0].a);
 | 
			
		||||
    puts(a3);
 | 
			
		||||
    puts(a4);
 | 
			
		||||
    puts(p);
 | 
			
		||||
    puts("world");
 | 
			
		||||
    printf("%s\n", "bla");
 | 
			
		||||
    puts(str_ar[0]);
 | 
			
		||||
    puts(str_ar[1]);
 | 
			
		||||
    puts(ss.a);
 | 
			
		||||
    puts(i >= 0 ? "one" : "two");
 | 
			
		||||
    puts(pa1);
 | 
			
		||||
    puts(pa2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ps(const char *s)
 | 
			
		||||
{
 | 
			
		||||
    int c;
 | 
			
		||||
| 
						 | 
				
			
			@ -511,8 +553,10 @@ void string_test()
 | 
			
		|||
        num(b);
 | 
			
		||||
        b = b * 2;
 | 
			
		||||
    }
 | 
			
		||||
    string_test2();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void if1t(int n, int a, int b, int c)
 | 
			
		||||
{
 | 
			
		||||
    if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue