YX Hao | 29 Jul 13:11 2014

How to optimize compiling sizeof const?

Hi there,

We know that tcc generates bigger binary file than gcc for non-small projects. But I'm not meaning the
optimization options.

Here I find the titled issue when I compile an html5 library (Google's "gumbo"). In the compiled object file
and linked binary file, that of tcc you can find the string to be calculated size of is stored, and you will
see it will not be used with a debugger, while gcc generates clean file with smaller size. The attached file
is a piece of code for testing.

For non-small projects, I think, the way of using "sizeof" like this could be common. And hundreds or
thousands of words can result in a considerable size.

Hope we can improve tcc in any aspect. Please consider this issue.

I only find out where it occurs, but can't tell why.
-------------------------------------------------------------------------
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, 
                                   int has_init, int v, char *asm_label,
                                   int scope)
{
...
    size = type_size(type, &align); /* <-- get a zero */
    tok_str_new(&init_str);
    if (size < 0 || (flexible_array && has_init)) {
    ...
    decl_initializer(type, NULL, 0, 1, 1); /* <-- will store the str */
    ...
    }
...
(Continue reading)

jiang | 29 Jul 03:36 2014

回复: tcc grammar problems

I am sorry, I do not have expressed good I mean. I want you sure, is tcc correct or gcc msvc correctly. If the gcc
msvc correct, I want to fix it.

Best regards
Jiang

Thomas Preud'homme <robotux <at> celest.fr>编写:

>Le dimanche 13 juillet 2014, 22:12:39 jiang a écrit :
>> Hello everyone!
>> 
>> (s->a = (s->b = (s->c = n + 4)));
>> 
>> 
>> gcc & msvc:
>> --> 30 / 30 / 126 // Because the return value is left
>> 
>> 
>> tcc
>> --> 254 / 30 / 126 // Because the return is the right value
>
>Since it works for the last two values I don't think it's that. It simply 
>looks like tcc compute n + 4 (254) and then tries to store it in each field 
>independently. It's a folding issue. Tcc records 254 in a CValue associated 
>with the SValue for n + 4. The problem is how this is propagated (folded) to 
>the three field access.
>
>> 
>> Shall tcc assignment modify what? Same with gcc&msvc.
>
(Continue reading)

Carlos Montiers | 17 Jul 05:39 2014
Picon

Correcting the prototype of __getmainargs and add validation to crt1.c

Hello.
I found that the current protoype of __getmainargs in crt1.c return void.
But according to the official internal.h from microsoft sdk it return int.

The documentation says: return 0 if successful; a negative value if unsuccessful.
I decompiled it from msvcrt.dll for windows xp.
And the only possible return value for error is -1 and is caused because a malloc cannot get memory.

It do a similar to this:
if ( globb ) {
    result = __setargv;
} else {
    result = _setargv();
}
if ( result >= 0 ) {
*argc = __argc;
*argv = __argv;
*env = _environ;
}
return result;

It only change the values of argc y argv if success the internal function that it call.
This internals functions __setargv and __setargv() ask for memory with malloc and if it is sucess set that pointer in the global variable __argv. if __argv is NULL because the memory cannot allocated on the heap. It return -1. Then __getmainargs check the return, if it is not a negative number it set argc, argv and env to the corresponding global variables: __argc, __argv, __environ.

Also i write a demo that demostrates that __getmainargs left untouched argc and argv if it fails. (attached)

When you run, it ful the heap (warning: it not free it. I tested on a a virtual machine with windows xp with 64 mb).

When you run it print:
Setting argc to -1 and argv to 1.
Content of argc:-1 argv:0x1
Calling __getmainargs.
__getmainargs failed!
Result of __getmainargs: -1
Content of argc:-1 argv:0x1

Beause it, if __getmainargs fails, it not set argv to NULL or argc to 0.
I added a if that check it, and print out a error message. But I not know if this is the recommended way for handle this error. A maybe possibles ways for handle it is:
set argc to 0 and argv to NULL and env to NULL
call to abort()
call to _exit(3)
call to exit(3)
call to ExitProcess(3)

I choose the last, and also I ad a error message, but it is can be optional:
This is the handle that I added:
if (__getmainargs(&argc, &argv, &env, 0, &start_info)) {
        // __getmainargs failed because possible few memory on the heap.
        fprintf(stderr, "Error getting the main args.");
        // terminate with exit code of 3, similar to abort()
        ExitProcess(3);
}

The documentation not says nothing about free argv, maybe because on sucess it points to the global variable __argv and maybe because it is global is free with exit functions (but i not know if this is true).

Here I prefer use ExitProcess instead of exit, because internally exit do some things and in the end it call to ExitProcess.
I think that ExitProcess is more speedy than exit, but maybe it not do the cleans that exit function makes. Exit function maybe deallocate the global variable __argv

Also, I found that avira antivir detect as false positive a executable compiled with tiny c when it not use ExitProcess, then have a crt using ExitProcess in some point avoid a false detection of our executable.

I use this in some crt for bypass a false detection:
/*
  This function is never called.
  Is used for avoid AntiVir false detection: TR/Crypt.XPACK.Gen
*/
void nothing(void)
{
    ExitProcess(0);
}

Because it I choose use ExitProcess for handle the error of __getmainargs function.


Carlos.











Attachment (poc_getmainargs.c): text/x-csrc, 1284 bytes
<div><div dir="ltr">
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div><div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>Hello.<br>
</div>I found that the current protoype of __getmainargs in crt1.c return void.<br>
</div>But according to the official internal.h from microsoft sdk it return int.<br><br>
</div>The documentation says: return 0 if successful; a negative value if unsuccessful.<br>
</div>I decompiled it from msvcrt.dll for windows xp.<br>
</div>And the only possible return value for error is -1 and is caused because a malloc cannot get memory.<br><br>
</div>It do a similar to this:<br>if ( globb ) {<br>&nbsp;&nbsp;&nbsp; result = __setargv;<br>} else {<br>&nbsp;&nbsp;&nbsp; result = _setargv();<br>}<br>if ( result &gt;= 0 ) {<br>*argc = __argc;<br>*argv = __argv;<br>*env = _environ;<br>}<br>return result;<br><br>
</div>It only change the values of argc y argv if success the internal function that it call.<br>
</div>This internals functions __setargv and __setargv() ask for memory with malloc and if it is sucess set that pointer in the global variable __argv. if __argv is NULL because the memory cannot allocated on the heap. It return -1. Then __getmainargs check the return, if it is not a negative number it set argc, argv and env to the corresponding global variables: __argc, __argv, __environ.<br><br>
</div></div>Also i write a demo that demostrates that __getmainargs left untouched argc and argv if it fails. (attached)<br><br>
</div>When you run, it ful the heap (warning: it not free it. I tested on a a virtual machine with windows xp with 64 mb).<br><br>
</div>When you run it print:<br>Setting argc to -1 and argv to 1.<br>Content of argc:-1 argv:0x1<br>Calling __getmainargs.<br>__getmainargs failed!<br>Result of __getmainargs: -1<br>Content of argc:-1 argv:0x1<br><br>
</div>Beause it, if __getmainargs fails, it not set argv to NULL or argc to 0.<br>
</div>I added a if that check it, and print out a error message. But I not know if this is the recommended way for handle this error. A maybe possibles ways for handle it is:<br>
set argc to 0 and argv to NULL and env to NULL<br>
</div>call to abort()<br>
</div>call to _exit(3)<br>call to exit(3)<br>
</div>
<div>call to ExitProcess(3)<br>
</div>
<div><br></div>
<div>I choose the last, and also I ad a error message, but it is can be optional:<br>
</div>
<div>This is the handle that I added:<br>if&nbsp;(__getmainargs(&amp;argc,&nbsp;&amp;argv,&nbsp;&amp;env,&nbsp;0,&nbsp;&amp;start_info))&nbsp;{
<div class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;__getmainargs&nbsp;failed&nbsp;because&nbsp;possible&nbsp;few&nbsp;memory&nbsp;on&nbsp;the&nbsp;heap.</div>
<div class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr,&nbsp;"Error&nbsp;getting&nbsp;the&nbsp;main&nbsp;args.");</div>
<div class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;terminate&nbsp;with&nbsp;exit&nbsp;code&nbsp;of&nbsp;3,&nbsp;similar&nbsp;to&nbsp;abort()</div>
<div class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExitProcess(3);</div>
<div class="">}</div>
<br>
</div>
<div>The documentation not says nothing about free argv, maybe because on sucess it points to the global variable __argv and maybe because it is global is free with exit functions (but i not know if this is true).<br><br>
</div>
<div>Here I prefer use ExitProcess instead of exit, because internally exit 
do some things and in the end it call to ExitProcess.<br>
</div>
<div>I think that ExitProcess is more speedy than exit, but maybe it not do the cleans that exit function makes. Exit function maybe deallocate the global variable __argv<br><br>
</div>
<div>Also, I found that avira antivir detect as false positive a executable compiled with tiny c when it not use ExitProcess, then have a crt using ExitProcess in some point avoid a false detection of our executable.<br><br>
</div>
<div>I use this in some crt for bypass a false detection:<br>/*<br>&nbsp; This function is never called.<br>&nbsp; Is used for avoid AntiVir false detection: TR/Crypt.XPACK.Gen<br>
*/<br>void nothing(void)<br>{<br>&nbsp;&nbsp;&nbsp; ExitProcess(0);<br>}<br><br>
</div>
<div>Because it I choose use ExitProcess for handle the error of __getmainargs function.<br><br><br>
</div>
<div>Carlos.<br>
</div>
<div>
<br><br>
</div>
<div>
<br><br><br><br><br><br>
</div>
<div>
<br><br><br>
</div>
</div></div>
James Russell Moore | 5 Jul 15:23 2014
Picon

Building Unicode applications with TCC in Windows.

Hello, I have a small utility which makes use of wide characters in Windows. It's written using _TCHAR though so it can be built with multibyte characters as well.

The main() function header is written as follows:

int _tmain(int argc, _TCHAR* argv[])

Translates to "main" in a multibyte build and "wmain" in a Unicode build, but TCC seems to expect a main() function instead of a wmain() one so it can't produce Unicode builds (I tried with a mob build as well).

Is is expected or is there something wrong? Would it be possible to make a modification to enable wmain() to be an entry point as well as main()?

Attached to this email is a small test case.

Thanks for your time anyway.
Attachment (test.c): text/x-csrc, 202 bytes
<div><div dir="ltr">
<div>Hello, I have a small utility which makes use of wide characters in Windows. It's written using _TCHAR though so it can be built with multibyte characters as well.</div>
<div><br></div>
<div>The main() function header is written as follows:</div>

<div><br></div>
<div>int _tmain(int argc, _TCHAR* argv[])</div>
<div><br></div>
<div>Translates to "main" in a multibyte build and "wmain" in a Unicode build, but TCC seems to expect a main() function instead of a wmain() one so it can't produce Unicode builds (I tried with a mob build as well).</div>

<div><br></div>
<div>Is is expected or is there something wrong? Would it be possible to make a modification to enable wmain() to be an entry point as well as main()?</div>
<div><br></div>
<div>Attached to this email is a small test case.</div>

<div><br></div>
<div>Thanks for your time anyway.</div>
</div></div>
jiang | 3 Jul 03:30 2014

回复: Request push

It doesn't matter, I'm not very urgent. thank you.but I need time to find their own patch mistake.

Best regards,

Jiang

Thomas Preud'homme <robotux <at> celest.fr>编写:

>Le mercredi 02 juillet 2014, 00:07:02 jiang a écrit :
>> I'm sorry, I was remiss.
>> I did not find a space with gitk.
>> This is my new commit:89000c18dc7d5ccb2687948f94fe49d392990dab
>
>That's great. Thanks. For the ";;;" patch I won't be able to review for 2 
>weeks as I'll be away from my computer. See if you can find someone else to 
>review or else wait for my return.
>
>Best regards,
>
>Thomas
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel <at> nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Thomas Preud'homme | 1 Jul 16:14 2014
Picon

Re: isxdigit conversion inconsistency with widechar

Le lundi 30 juin 2014, 15:03:35 Carlos Montiers a écrit :
> 
> Yes. It is not a bug. But, I post this for the knowledge. I inspect
> mscvrt.dll and isxdigit internally call to _isctype. Then I think is more
> speedy call directly to _isctype instead of isxdigit. But the current macro
> of tiny c not call to it like the counterpart iswxdigit. Because it I post
> my little fix:
> 
> #undef        isxdigit
> #undef        iswxdigit
> #define        isxdigit(d)      _isctype(d, _HEX)
> #define        iswxdigit(d)    iswctype(d, _HEX)

If you can provide number that shows it's indeed slower then it is indeed a 
bug and someone might fix it someday. Else I doubt somebody will feel motivated 
enough to change this (I might be wrong).

Best regards,

Thomas
Le lundi 30 juin 2014, 15:03:35 Carlos Montiers a écrit :
> 
> Yes. It is not a bug. But, I post this for the knowledge. I inspect
> mscvrt.dll and isxdigit internally call to _isctype. Then I think is more
> speedy call directly to _isctype instead of isxdigit. But the current macro
> of tiny c not call to it like the counterpart iswxdigit. Because it I post
> my little fix:
> 
> #undef        isxdigit
> #undef        iswxdigit
> #define        isxdigit(d)      _isctype(d, _HEX)
> #define        iswxdigit(d)    iswctype(d, _HEX)

If you can provide number that shows it's indeed slower then it is indeed a 
bug and someone might fix it someday. Else I doubt somebody will feel motivated 
enough to change this (I might be wrong).

Best regards,

Thomas
jiang | 30 Jun 16:58 2014

回复: Request push

I'm sorry! Is I am too impatient. Thank you for your remind and Suggestions. I'll take the time to put a bug in
greater detail.

Best regards,

jiang

Thomas Preud'homme <robotux <at> celest.fr>编写:

>Le lundi 30 juin 2014, 16:49:02 jiang a écrit :
>> Struct improved algorithms and add struct warnings and other warnings.
>
>Hi Jiang,
>
>> 
>> The following can be compiled:
>> struct st{int a;;;;;;;};
>> 
>> If you do not have advice, tomorrow pushed into the mob.
>
>No Jiang, that's not how it works. There is several problem with this request:
>
>1) You need to realize that we are all volunteer spending some of our free 
>time to improve tcc. We don't necessarily check emails about tcc everyday and 
>anyway 1 day is too short to review. Another consequence of this is that we 
>don't have to answer within a given delay. We will do our best to answer but 
>you just need to wait. Of course if too much time (like 2 weeks) pass without 
>answer you can ping to ask if we saw your email. And finally I think in your 
>case you should not commit without an approval first. Eventually, when your 
>commit will start to improve we might tell you that you don't need to ask for 
>a review anymore.
>
>2) I gave you some comments on another patch. Before asking for another review 
>you could maybe post a new version that fixes all my comments. It gives the 
>feeling that you don't want to address the remarks and discourages people to 
>review your patches.
>
>3) Don't bundle several changes in one patch. It makes it more difficult to 
>review. So you make one patch that fixes the bug you mentions and others (or 
>maybe just one other, it depends how big it is) with the warnings
>
>4) Your patch contains some formatting issues:
>
>+                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT){
>+                            tcc_warning("declaration does not
declare 
>anything");
>+                            break;
>+                        }if (type_size(&type1, &align) < 0) {
>+                            if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY))
>+                                flexible = 1;
>+                            else
>+                                tcc_error("field '%s' has
incomplete type", 
>get_tok_str(v, NULL));
>                         }
>
>There should be a space between the closing parenthesis ')' and the opening 
>curly brace '{'. The second "if" should be on a new line or should be preceded 
>by a "else"
>
>5) The commit message is not very informative. For the commit with the bugfix 
>you could say "Allow tcc to parse:" and then the example. See commit 
>82969f045c99b4d1ef833de35117c17b326b46c0 for an example. You can also simply 
>explain what bug you fix "Fix parsing of arbitrary number of semicolons" or 
>something better and that brings me to the next comment.
>
>6) You need to understand how a language is designed.
>
>-                parse_btype(&btype, &ad);
>+                if(!parse_btype(&btype, &ad)){
>+                    if (tok == ';'){
>+                        skip(';');
>+                        continue;
>
>Here you are saying that it's ok to have struct st {int a;;;;;} but not struct 
>st {int a:10;;;;}. A better place to add such a check would be near the end of 
>the function, around the "skip(';'). You need to understand why this is 
>authorized. So as an exercise grab the C99 standard at [1] and tell me why 
>this is authorized. Hint: start to read from section 6.7.2.1. Definitions are 
>recursive, so you need to browse quite a lot to understand things. Try to tell 
>me which lexical elements to follow (sorry, I don't know the proper term, 
>shame on me) to create your testcase. Something like:
>
>struct-or-union-specifier
>  -> struct-or-union
>  -> identifier (no need to detail here)
>  -> struct-declaration-list
>     -> struct-declaration
>
>etc…
>
>[1] http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
>
>Best regards,
>
>Thomas
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel <at> nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
jiang | 30 Jun 10:49 2014

Re: Request push

Struct improved algorithms and add struct warnings and other warnings.

The following can be compiled:
struct st{int a;;;;;;;};

If you do not have advice, tomorrow pushed into the mob.

jiang
commit 8be2fbd82ef16c8f846fccb46689827ed37997eb
Author: jiang <30155751@...>
Date:   Mon Jun 30 16:40:16 2014 +0800

    Add warning

diff --git a/libtcc.c b/libtcc.c
index 7caa7c1..79a2d2c 100644
--- a/libtcc.c
+++ b/libtcc.c
 <at>  <at>  -1397,8 +1397,9  <at>  <at>  static const FlagDef warning_defs[] = {
     { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
     { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
     { offsetof(TCCState, warn_error), 0, "error" },
-    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
-      "implicit-function-declaration" },
+    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
"implicit-function-declaration" },
+    { offsetof(TCCState, warn_return_type), WD_ALL, "return-type" },
+    { offsetof(TCCState, warn_char_subscripts), WD_ALL, "char-subscripts" },
 };

 ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
diff --git a/tcc.h b/tcc.h
index c93cedf..596b22f 100644
--- a/tcc.h
+++ b/tcc.h
 <at>  <at>  -594,6 +594,8  <at>  <at>  struct TCCState {
     int warn_error;
     int warn_none;
     int warn_implicit_function_declaration;
+    int warn_return_type;
+    int warn_char_subscripts;

     /* compile with debug symbol (and use them if error during execution) */
     int do_debug;
diff --git a/tccgen.c b/tccgen.c
index 1a89d4a..227864e 100644
--- a/tccgen.c
+++ b/tccgen.c
 <at>  <at>  -2898,42 +2898,47  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
             offset = 0;
             flexible = 0;
             while (tok != '}') {
-                parse_btype(&btype, &ad);
+                if(!parse_btype(&btype, &ad)){
+                    if (tok == ';'){
+                        skip(';');
+                        continue;
+                    }else if(tok == TOK_EOF || tok == '{')
+                        expect("specifier-qualifier-list at end of input");
+                }
                 while (1) {
-		    if (flexible)
-		        tcc_error("flexible array member '%s' not at the end of struct",
-                              get_tok_str(v, NULL));
+                    if (flexible)
+                        tcc_error("flexible array member '%s' not at the end of struct", get_tok_str(v, NULL));
                     bit_size = -1;
                     v = 0;
                     type1 = btype;
                     if (tok != ':') {
                         type_decl(&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT);
-                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT)
-                            expect("identifier");
-                        if (type_size(&type1, &align) < 0) {
-			    if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c)
-			        flexible = 1;
-			    else
-			        tcc_error("field '%s' has incomplete type",
-                                      get_tok_str(v, NULL));
+                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT){
+                            tcc_warning("declaration does not declare anything");
+                            break;
+                        }if (type_size(&type1, &align) < 0) {
+                            if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY))
+                                flexible = 1;
+                            else
+                                tcc_error("field '%s' has incomplete type", get_tok_str(v, NULL));
                         }
                         if ((type1.t & VT_BTYPE) == VT_FUNC ||
                             (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE)))
-                            tcc_error("invalid type for '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("invalid type for '%s'", get_tok_str(v, NULL));
                     }
                     if (tok == ':') {
                         next();
                         bit_size = expr_const();
                         /* XXX: handle v = 0 case for messages */
                         if (bit_size < 0)
-                            tcc_error("negative width in bit-field '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("negative width in bit-field '%s'", get_tok_str(v, NULL));
                         if (v && bit_size == 0)
-                            tcc_error("zero width for bit-field '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("zero width for bit-field '%s'", get_tok_str(v, NULL));
                     }
-                    size = type_size(&type1, &align);
+                    if(type1.t & VT_VLA)
+                        size = 0, align = 1;
+                    else
+                        size = type_size(&type1, &align);
                     if (ad.a.aligned) {
                         if (align < ad.a.aligned)
                             align = ad.a.aligned;
 <at>  <at>  -2946,12 +2951,9  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
                     lbit_pos = 0;
                     if (bit_size >= 0) {
                         bt = type1.t & VT_BTYPE;
-                        if (bt != VT_INT && 
-                            bt != VT_BYTE && 
-                            bt != VT_SHORT &&
-                            bt != VT_BOOL &&
-                            bt != VT_ENUM &&
-                            bt != VT_LLONG)
+                        if (bt != VT_INT && bt != VT_BYTE &&
+                            bt != VT_SHORT && bt != VT_BOOL &&
+                            bt != VT_ENUM && bt != VT_LLONG)
                             tcc_error("bitfields must have scalar type");
                         bsize = size * 8;
                         if (bit_size > bsize) {
 <at>  <at>  -3023,13 +3025,19  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
                         *ps = ss;
                         ps = &ss->next;
                     }
-                    if (tok == ';' || tok == TOK_EOF)
+                    if (tok == ';' || tok == '}')
                         break;
                     skip(',');
                 }
-                skip(';');
+                if(tok == '}'){
+                    tcc_warning("no ';' at end of struct or union");
+                    break;
+                }else
+                    skip(';');
             }
-            skip('}');
+            next();
+            if (!c && flexible)
+                tcc_error("flexible array member '%s' in otherwise empty struct", get_tok_str(v, NULL));
             /* store size and alignment */
             s->c = (c + maxalign - 1) & -maxalign; 
             s->r = maxalign;
 <at>  <at>  -4037,6 +4045,8  <at>  <at>  ST_FUNC void unary(void)
         } else if (tok == '[') {
             next();
             gexpr();
+            if(tcc_state->warn_char_subscripts && (vtop->type.t & (VT_BTYPE|VT_DEFSIGN|VT_UNSIGNED)) == VT_BYTE)
+                tcc_warning("array subscript has type 'char'");
             gen_op('+');
             indir();
             skip(']');
 <at>  <at>  -5510,6 +5520,8  <at>  <at>  static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
     Sym *flexible_array;

     flexible_array = NULL;
+    if (has_init && (type->t & VT_VLA))
+        tcc_error("Variable length array cannot be initialized");
     if ((type->t & VT_BTYPE) == VT_STRUCT) {
         Sym *field = type->ref->next;
         if (field) {
 <at>  <at>  -5907,12 +5919,13  <at>  <at>  ST_FUNC void gen_inline_functions(void)
 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
 static int decl0(int l, int is_for_loop_init)
 {
-    int v, has_init, r;
+    int v, has_init, r, imp;
     CType type, btype;
     Sym *sym;
     AttributeDef ad;

     while (1) {
+        imp = 0;
         if (!parse_btype(&btype, &ad)) {
             if (is_for_loop_init)
                 return 0;
 <at>  <at>  -5922,11 +5935,13  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                 next();
                 continue;
             }
-            if (l == VT_CONST &&
-                (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
+            if (l == VT_CONST){
+                if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3){
                 /* global asm block */
-                asm_global_instr();
-                continue;
+                    asm_global_instr();
+                    continue;
+                }
+                imp = 1;
             }
             /* special test for old K&R protos without explicit int
                type. Only accepted when defining global data */
 <at>  <at>  -5934,10 +5949,15  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                 break;
             btype.t = VT_INT;
         }
-        if (((btype.t & VT_BTYPE) == VT_ENUM ||
-             (btype.t & VT_BTYPE) == VT_STRUCT) && 
-            tok == ';') {
+        if (tok == ';') {
+            int bt = btype.t & VT_BTYPE;
             /* we accept no variable after */
+            if(btype.t & (VT_CONSTANT|VT_VOLATILE))
+                tcc_warning("useless type qualifier in empty declaration.'%s'before", get_tok_str(tok, NULL));
+            if(bt != VT_STRUCT && bt != VT_ENUM)
+                tcc_warning("useless type name in empty declaration '%s'", get_tok_str(tok, NULL));
+            if((bt == VT_STRUCT) && ((btype.ref->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM))
+                tcc_warning("unnamed struct/union that defines no instances");
             next();
             continue;
         }
 <at>  <at>  -6097,6 +6117,9  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                     sym->a = ad.a;
                     sym->type.t |= VT_TYPEDEF;
                 } else {
+                    if(imp && (type.t & VT_BTYPE) != VT_FUNC)
+                        tcc_warning("data definition has no type or storage class: '%s'",
+                            get_tok_str(v, NULL));
                     r = 0;
                     if ((type.t & VT_BTYPE) == VT_FUNC) {
                         /* external function definition */
 <at>  <at>  -6108,8 +6131,6  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                         r |= lvalue_type(type.t);
                     }
                     has_init = (tok == '=');
-                    if (has_init && (type.t & VT_VLA))
-                        tcc_error("Variable length array cannot be initialized");
                     if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) ||
                         ((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
                          !has_init && l == VT_CONST && type.ref->c < 0)) {
diff --git a/tests/tests2/46_grep.c b/tests/tests2/46_grep.c
index 3123bc3..d789ee0 100644
--- a/tests/tests2/46_grep.c
+++ b/tests/tests2/46_grep.c
 <at>  <at>  -15,6 +15,7  <at>  <at> 
  * privileges were granted by DECUS.
  */
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>

 /*
diff --git a/tests/tests2/64_macro_nesting.c b/tests/tests2/64_macro_nesting.c
index 44b582f..2123a75 100644
--- a/tests/tests2/64_macro_nesting.c
+++ b/tests/tests2/64_macro_nesting.c
 <at>  <at>  -1,3 +1,4  <at>  <at> 
+#include <stdio.h>
 #define CAT2(a,b) a##b
 #define CAT(a,b) CAT2(a,b)
 #define AB(x) CAT(x,y)
diff --git a/tests/tests2/70_warn_test.c b/tests/tests2/70_warn_test.c
new file mode 100644
index 0000000..5543426
--- /dev/null
+++ b/tests/tests2/70_warn_test.c
 <at>  <at>  -0,0 +1,18  <at>  <at> 
+#include <stdio.h>
+#define uint8_t unsigned char
+const struct {
+    const uint8_t code
+};
+
+a;
+b,c;
+
+int main(void)
+{
+    char c = 1;
+    int b[2];
+    b[c] = 9;
+    printf("%d\n", b[c]);
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/70_warn_test.expect b/tests/tests2/70_warn_test.expect
new file mode 100644
index 0000000..bae7348
--- /dev/null
+++ b/tests/tests2/70_warn_test.expect
 <at>  <at>  -0,0 +1,10  <at>  <at> 
+70_warn_test.c:5: warning: no ';' at end of struct or union
+70_warn_test.c:5: warning: useless type qualifier in empty declaration.';'before
+70_warn_test.c:5: warning: unnamed struct/union that defines no instances
+70_warn_test.c:7: warning: data definition has no type or storage class: 'a'
+70_warn_test.c:8: warning: data definition has no type or storage class: 'b'
+70_warn_test.c:8: warning: data definition has no type or storage class: 'c'
+70_warn_test.c:14: warning: array subscript has type 'char'
+70_warn_test.c:15: warning: array subscript has type 'char'
+9
+ok
diff --git a/tests/tests2/71_err_struct.c b/tests/tests2/71_err_struct.c
new file mode 100644
index 0000000..276c993
--- /dev/null
+++ b/tests/tests2/71_err_struct.c
 <at>  <at>  -0,0 +1,8  <at>  <at> 
+typedef struct {
+    const uint8_t* code;
+} st;
+
+int main(void)
+{
+    return 0;
+}
diff --git a/tests/tests2/71_err_struct.expect b/tests/tests2/71_err_struct.expect
new file mode 100644
index 0000000..239c174
--- /dev/null
+++ b/tests/tests2/71_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+71_err_struct.c:2: error: ',' expected (got "*")
diff --git a/tests/tests2/72_err_struct.c b/tests/tests2/72_err_struct.c
new file mode 100644
index 0000000..e3d7afd
--- /dev/null
+++ b/tests/tests2/72_err_struct.c
 <at>  <at>  -0,0 +1,11  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int;
+    int;
+;{};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/72_err_struct.expect b/tests/tests2/72_err_struct.expect
new file mode 100644
index 0000000..7aaf45a
--- /dev/null
+++ b/tests/tests2/72_err_struct.expect
 <at>  <at>  -0,0 +1,3  <at>  <at> 
+72_err_struct.c:3: warning: declaration does not declare anything
+72_err_struct.c:4: warning: declaration does not declare anything
+72_err_struct.c:5: error: specifier-qualifier-list at end of input expected
diff --git a/tests/tests2/73_err_struct.c b/tests/tests2/73_err_struct.c
new file mode 100644
index 0000000..6851b76
--- /dev/null
+++ b/tests/tests2/73_err_struct.c
 <at>  <at>  -0,0 +1,11  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int a[];
+    int b;
+};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/73_err_struct.expect b/tests/tests2/73_err_struct.expect
new file mode 100644
index 0000000..d42b710
--- /dev/null
+++ b/tests/tests2/73_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+73_err_struct.c:4: error: flexible array member 'a' not at the end of struct
diff --git a/tests/tests2/74_err_struct.c b/tests/tests2/74_err_struct.c
new file mode 100644
index 0000000..40c5fd4
--- /dev/null
+++ b/tests/tests2/74_err_struct.c
 <at>  <at>  -0,0 +1,10  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int a[];
+};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/74_err_struct.expect b/tests/tests2/74_err_struct.expect
new file mode 100644
index 0000000..2338ad0
--- /dev/null
+++ b/tests/tests2/74_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+74_err_struct.c:4: error: flexible array member 'a' in otherwise empty struct
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 64532a1..104d456 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
 <at>  <at>  -84,7 +84,12  <at>  <at>  TESTS =	\
  66_macro_concat_end.test \
  67_macro_concat.test \
  68_macro_concat.test \
- 69_macro_concat.test
+ 69_macro_concat.test \
+ 70_warn_test.test \
+ 71_err_struct.test \
+ 72_err_struct.test \
+ 73_err_struct.test \
+ 74_err_struct.test

 # 34_array_assignment.test -- array assignment is not in C standard

 <at>  <at>  -109,10 +114,10  <at>  <at>  all test: $(filter-out $(SKIP),$(TESTS))
 %.test: %.c %.expect
 	 <at> echo Test: $*...

-	 <at> $(TCC) -run $< $(ARGS) >$*.output 2>&1 || true
+	 <at> $(TCC) -Wall -run $< $(ARGS) >$*.output 2>&1 || true
 	 <at> diff -bu $*.expect $*.output && rm -f $*.output

-	 <at> ($(TCC) $< -o $*.exe && ./$*.exe $(ARGS)) >$*.output2 2>&1 || true
+	 <at> ($(TCC) -Wall $< -o $*.exe && ./$*.exe $(ARGS)) >$*.output2 2>&1 || true
 	 <at> diff -bu $*.expect $*.output2 && rm -f $*.output2 $*.exe

 clean:
commit 8be2fbd82ef16c8f846fccb46689827ed37997eb
Author: jiang <30155751@...>
Date:   Mon Jun 30 16:40:16 2014 +0800

    Add warning

diff --git a/libtcc.c b/libtcc.c
index 7caa7c1..79a2d2c 100644
--- a/libtcc.c
+++ b/libtcc.c
 <at>  <at>  -1397,8 +1397,9  <at>  <at>  static const FlagDef warning_defs[] = {
     { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
     { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
     { offsetof(TCCState, warn_error), 0, "error" },
-    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
-      "implicit-function-declaration" },
+    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
"implicit-function-declaration" },
+    { offsetof(TCCState, warn_return_type), WD_ALL, "return-type" },
+    { offsetof(TCCState, warn_char_subscripts), WD_ALL, "char-subscripts" },
 };

 ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
diff --git a/tcc.h b/tcc.h
index c93cedf..596b22f 100644
--- a/tcc.h
+++ b/tcc.h
 <at>  <at>  -594,6 +594,8  <at>  <at>  struct TCCState {
     int warn_error;
     int warn_none;
     int warn_implicit_function_declaration;
+    int warn_return_type;
+    int warn_char_subscripts;

     /* compile with debug symbol (and use them if error during execution) */
     int do_debug;
diff --git a/tccgen.c b/tccgen.c
index 1a89d4a..227864e 100644
--- a/tccgen.c
+++ b/tccgen.c
 <at>  <at>  -2898,42 +2898,47  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
             offset = 0;
             flexible = 0;
             while (tok != '}') {
-                parse_btype(&btype, &ad);
+                if(!parse_btype(&btype, &ad)){
+                    if (tok == ';'){
+                        skip(';');
+                        continue;
+                    }else if(tok == TOK_EOF || tok == '{')
+                        expect("specifier-qualifier-list at end of input");
+                }
                 while (1) {
-		    if (flexible)
-		        tcc_error("flexible array member '%s' not at the end of struct",
-                              get_tok_str(v, NULL));
+                    if (flexible)
+                        tcc_error("flexible array member '%s' not at the end of struct", get_tok_str(v, NULL));
                     bit_size = -1;
                     v = 0;
                     type1 = btype;
                     if (tok != ':') {
                         type_decl(&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT);
-                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT)
-                            expect("identifier");
-                        if (type_size(&type1, &align) < 0) {
-			    if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c)
-			        flexible = 1;
-			    else
-			        tcc_error("field '%s' has incomplete type",
-                                      get_tok_str(v, NULL));
+                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT){
+                            tcc_warning("declaration does not declare anything");
+                            break;
+                        }if (type_size(&type1, &align) < 0) {
+                            if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY))
+                                flexible = 1;
+                            else
+                                tcc_error("field '%s' has incomplete type", get_tok_str(v, NULL));
                         }
                         if ((type1.t & VT_BTYPE) == VT_FUNC ||
                             (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE)))
-                            tcc_error("invalid type for '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("invalid type for '%s'", get_tok_str(v, NULL));
                     }
                     if (tok == ':') {
                         next();
                         bit_size = expr_const();
                         /* XXX: handle v = 0 case for messages */
                         if (bit_size < 0)
-                            tcc_error("negative width in bit-field '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("negative width in bit-field '%s'", get_tok_str(v, NULL));
                         if (v && bit_size == 0)
-                            tcc_error("zero width for bit-field '%s'", 
-                                  get_tok_str(v, NULL));
+                            tcc_error("zero width for bit-field '%s'", get_tok_str(v, NULL));
                     }
-                    size = type_size(&type1, &align);
+                    if(type1.t & VT_VLA)
+                        size = 0, align = 1;
+                    else
+                        size = type_size(&type1, &align);
                     if (ad.a.aligned) {
                         if (align < ad.a.aligned)
                             align = ad.a.aligned;
 <at>  <at>  -2946,12 +2951,9  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
                     lbit_pos = 0;
                     if (bit_size >= 0) {
                         bt = type1.t & VT_BTYPE;
-                        if (bt != VT_INT && 
-                            bt != VT_BYTE && 
-                            bt != VT_SHORT &&
-                            bt != VT_BOOL &&
-                            bt != VT_ENUM &&
-                            bt != VT_LLONG)
+                        if (bt != VT_INT && bt != VT_BYTE &&
+                            bt != VT_SHORT && bt != VT_BOOL &&
+                            bt != VT_ENUM && bt != VT_LLONG)
                             tcc_error("bitfields must have scalar type");
                         bsize = size * 8;
                         if (bit_size > bsize) {
 <at>  <at>  -3023,13 +3025,19  <at>  <at>  static void struct_decl(CType *type, int u, int tdef)
                         *ps = ss;
                         ps = &ss->next;
                     }
-                    if (tok == ';' || tok == TOK_EOF)
+                    if (tok == ';' || tok == '}')
                         break;
                     skip(',');
                 }
-                skip(';');
+                if(tok == '}'){
+                    tcc_warning("no ';' at end of struct or union");
+                    break;
+                }else
+                    skip(';');
             }
-            skip('}');
+            next();
+            if (!c && flexible)
+                tcc_error("flexible array member '%s' in otherwise empty struct", get_tok_str(v, NULL));
             /* store size and alignment */
             s->c = (c + maxalign - 1) & -maxalign; 
             s->r = maxalign;
 <at>  <at>  -4037,6 +4045,8  <at>  <at>  ST_FUNC void unary(void)
         } else if (tok == '[') {
             next();
             gexpr();
+            if(tcc_state->warn_char_subscripts && (vtop->type.t & (VT_BTYPE|VT_DEFSIGN|VT_UNSIGNED)) == VT_BYTE)
+                tcc_warning("array subscript has type 'char'");
             gen_op('+');
             indir();
             skip(']');
 <at>  <at>  -5510,6 +5520,8  <at>  <at>  static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
     Sym *flexible_array;

     flexible_array = NULL;
+    if (has_init && (type->t & VT_VLA))
+        tcc_error("Variable length array cannot be initialized");
     if ((type->t & VT_BTYPE) == VT_STRUCT) {
         Sym *field = type->ref->next;
         if (field) {
 <at>  <at>  -5907,12 +5919,13  <at>  <at>  ST_FUNC void gen_inline_functions(void)
 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
 static int decl0(int l, int is_for_loop_init)
 {
-    int v, has_init, r;
+    int v, has_init, r, imp;
     CType type, btype;
     Sym *sym;
     AttributeDef ad;

     while (1) {
+        imp = 0;
         if (!parse_btype(&btype, &ad)) {
             if (is_for_loop_init)
                 return 0;
 <at>  <at>  -5922,11 +5935,13  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                 next();
                 continue;
             }
-            if (l == VT_CONST &&
-                (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
+            if (l == VT_CONST){
+                if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3){
                 /* global asm block */
-                asm_global_instr();
-                continue;
+                    asm_global_instr();
+                    continue;
+                }
+                imp = 1;
             }
             /* special test for old K&R protos without explicit int
                type. Only accepted when defining global data */
 <at>  <at>  -5934,10 +5949,15  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                 break;
             btype.t = VT_INT;
         }
-        if (((btype.t & VT_BTYPE) == VT_ENUM ||
-             (btype.t & VT_BTYPE) == VT_STRUCT) && 
-            tok == ';') {
+        if (tok == ';') {
+            int bt = btype.t & VT_BTYPE;
             /* we accept no variable after */
+            if(btype.t & (VT_CONSTANT|VT_VOLATILE))
+                tcc_warning("useless type qualifier in empty declaration.'%s'before", get_tok_str(tok, NULL));
+            if(bt != VT_STRUCT && bt != VT_ENUM)
+                tcc_warning("useless type name in empty declaration '%s'", get_tok_str(tok, NULL));
+            if((bt == VT_STRUCT) && ((btype.ref->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM))
+                tcc_warning("unnamed struct/union that defines no instances");
             next();
             continue;
         }
 <at>  <at>  -6097,6 +6117,9  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                     sym->a = ad.a;
                     sym->type.t |= VT_TYPEDEF;
                 } else {
+                    if(imp && (type.t & VT_BTYPE) != VT_FUNC)
+                        tcc_warning("data definition has no type or storage class: '%s'",
+                            get_tok_str(v, NULL));
                     r = 0;
                     if ((type.t & VT_BTYPE) == VT_FUNC) {
                         /* external function definition */
 <at>  <at>  -6108,8 +6131,6  <at>  <at>  static int decl0(int l, int is_for_loop_init)
                         r |= lvalue_type(type.t);
                     }
                     has_init = (tok == '=');
-                    if (has_init && (type.t & VT_VLA))
-                        tcc_error("Variable length array cannot be initialized");
                     if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) ||
                         ((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
                          !has_init && l == VT_CONST && type.ref->c < 0)) {
diff --git a/tests/tests2/46_grep.c b/tests/tests2/46_grep.c
index 3123bc3..d789ee0 100644
--- a/tests/tests2/46_grep.c
+++ b/tests/tests2/46_grep.c
 <at>  <at>  -15,6 +15,7  <at>  <at> 
  * privileges were granted by DECUS.
  */
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>

 /*
diff --git a/tests/tests2/64_macro_nesting.c b/tests/tests2/64_macro_nesting.c
index 44b582f..2123a75 100644
--- a/tests/tests2/64_macro_nesting.c
+++ b/tests/tests2/64_macro_nesting.c
 <at>  <at>  -1,3 +1,4  <at>  <at> 
+#include <stdio.h>
 #define CAT2(a,b) a##b
 #define CAT(a,b) CAT2(a,b)
 #define AB(x) CAT(x,y)
diff --git a/tests/tests2/70_warn_test.c b/tests/tests2/70_warn_test.c
new file mode 100644
index 0000000..5543426
--- /dev/null
+++ b/tests/tests2/70_warn_test.c
 <at>  <at>  -0,0 +1,18  <at>  <at> 
+#include <stdio.h>
+#define uint8_t unsigned char
+const struct {
+    const uint8_t code
+};
+
+a;
+b,c;
+
+int main(void)
+{
+    char c = 1;
+    int b[2];
+    b[c] = 9;
+    printf("%d\n", b[c]);
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/70_warn_test.expect b/tests/tests2/70_warn_test.expect
new file mode 100644
index 0000000..bae7348
--- /dev/null
+++ b/tests/tests2/70_warn_test.expect
 <at>  <at>  -0,0 +1,10  <at>  <at> 
+70_warn_test.c:5: warning: no ';' at end of struct or union
+70_warn_test.c:5: warning: useless type qualifier in empty declaration.';'before
+70_warn_test.c:5: warning: unnamed struct/union that defines no instances
+70_warn_test.c:7: warning: data definition has no type or storage class: 'a'
+70_warn_test.c:8: warning: data definition has no type or storage class: 'b'
+70_warn_test.c:8: warning: data definition has no type or storage class: 'c'
+70_warn_test.c:14: warning: array subscript has type 'char'
+70_warn_test.c:15: warning: array subscript has type 'char'
+9
+ok
diff --git a/tests/tests2/71_err_struct.c b/tests/tests2/71_err_struct.c
new file mode 100644
index 0000000..276c993
--- /dev/null
+++ b/tests/tests2/71_err_struct.c
 <at>  <at>  -0,0 +1,8  <at>  <at> 
+typedef struct {
+    const uint8_t* code;
+} st;
+
+int main(void)
+{
+    return 0;
+}
diff --git a/tests/tests2/71_err_struct.expect b/tests/tests2/71_err_struct.expect
new file mode 100644
index 0000000..239c174
--- /dev/null
+++ b/tests/tests2/71_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+71_err_struct.c:2: error: ',' expected (got "*")
diff --git a/tests/tests2/72_err_struct.c b/tests/tests2/72_err_struct.c
new file mode 100644
index 0000000..e3d7afd
--- /dev/null
+++ b/tests/tests2/72_err_struct.c
 <at>  <at>  -0,0 +1,11  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int;
+    int;
+;{};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/72_err_struct.expect b/tests/tests2/72_err_struct.expect
new file mode 100644
index 0000000..7aaf45a
--- /dev/null
+++ b/tests/tests2/72_err_struct.expect
 <at>  <at>  -0,0 +1,3  <at>  <at> 
+72_err_struct.c:3: warning: declaration does not declare anything
+72_err_struct.c:4: warning: declaration does not declare anything
+72_err_struct.c:5: error: specifier-qualifier-list at end of input expected
diff --git a/tests/tests2/73_err_struct.c b/tests/tests2/73_err_struct.c
new file mode 100644
index 0000000..6851b76
--- /dev/null
+++ b/tests/tests2/73_err_struct.c
 <at>  <at>  -0,0 +1,11  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int a[];
+    int b;
+};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/73_err_struct.expect b/tests/tests2/73_err_struct.expect
new file mode 100644
index 0000000..d42b710
--- /dev/null
+++ b/tests/tests2/73_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+73_err_struct.c:4: error: flexible array member 'a' not at the end of struct
diff --git a/tests/tests2/74_err_struct.c b/tests/tests2/74_err_struct.c
new file mode 100644
index 0000000..40c5fd4
--- /dev/null
+++ b/tests/tests2/74_err_struct.c
 <at>  <at>  -0,0 +1,10  <at>  <at> 
+#include <stdio.h>
+typedef struct {
+    int a[];
+};
+
+int main(void)
+{
+    printf("ok\n");
+    return 0;
+}
diff --git a/tests/tests2/74_err_struct.expect b/tests/tests2/74_err_struct.expect
new file mode 100644
index 0000000..2338ad0
--- /dev/null
+++ b/tests/tests2/74_err_struct.expect
 <at>  <at>  -0,0 +1  <at>  <at> 
+74_err_struct.c:4: error: flexible array member 'a' in otherwise empty struct
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 64532a1..104d456 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
 <at>  <at>  -84,7 +84,12  <at>  <at>  TESTS =	\
  66_macro_concat_end.test \
  67_macro_concat.test \
  68_macro_concat.test \
- 69_macro_concat.test
+ 69_macro_concat.test \
+ 70_warn_test.test \
+ 71_err_struct.test \
+ 72_err_struct.test \
+ 73_err_struct.test \
+ 74_err_struct.test

 # 34_array_assignment.test -- array assignment is not in C standard

 <at>  <at>  -109,10 +114,10  <at>  <at>  all test: $(filter-out $(SKIP),$(TESTS))
 %.test: %.c %.expect
 	 <at> echo Test: $*...

-	 <at> $(TCC) -run $< $(ARGS) >$*.output 2>&1 || true
+	 <at> $(TCC) -Wall -run $< $(ARGS) >$*.output 2>&1 || true
 	 <at> diff -bu $*.expect $*.output && rm -f $*.output

-	 <at> ($(TCC) $< -o $*.exe && ./$*.exe $(ARGS)) >$*.output2 2>&1 || true
+	 <at> ($(TCC) -Wall $< -o $*.exe && ./$*.exe $(ARGS)) >$*.output2 2>&1 || true
 	 <at> diff -bu $*.expect $*.output2 && rm -f $*.output2 $*.exe

 clean:
Carlos Montiers | 30 Jun 04:10 2014
Picon

isxdigit conversion inconsistency with widechar

Hello.
Currently, in the last version (from git) of tiny c, when you use the function:

isxdigit it produce this call: isxdigit

but when you use the widechar version: iswxdigit :

iswxdigit produce this call: iswctype(d, _HEX)

Then, when you use isxdigit tiny c would be generate the call to:
_isctype(d, _HEX)

I use this little fix:
#undef        isxdigit
#undef        iswxdigit
#define        isxdigit(d)      _isctype(d, _HEX)
#define        iswxdigit(d)    iswctype(d, _HEX)


Carlos.


<div><div dir="ltr">
<div>
<div>
<div>
<div>
<div>Hello.<br>Currently, in the last version (from git) of tiny c, when you use the function:<br><br>isxdigit it produce this call: isxdigit<br><br>
</div>but when you use the widechar version: iswxdigit :<br><br>iswxdigit produce this call: iswctype(d, _HEX)<br><br>
</div>Then, when you use isxdigit tiny c would be generate the call to:<br>_isctype(d, _HEX)<br>
</div>
<br>
</div>I use this little fix:<br>#undef&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; isxdigit<br>
#undef&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iswxdigit<br>#define&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; isxdigit(d)&nbsp;&nbsp;&nbsp; &nbsp; _isctype(d, _HEX)<br>#define&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iswxdigit(d)&nbsp;&nbsp;&nbsp; iswctype(d, _HEX)<br><br><br>
</div>
<div>Carlos.<br><br>
</div>
<br>
</div></div>
Carlos Montiers | 30 Jun 03:38 2014
Picon

Problem using alloca

Hello.
I requesting memory from the stack using the function alloca.
I know that the use of it is discourage, but I want use it anyways.

I write a code for windows that use it and I tested ok, but only when I compile with gcc. Compiling it with tiny c fails, the program crash.
Maybe is a bug of tiny c.


This is the code:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <malloc.h>
#include <setjmp.h>

int _resetstkoflw ( void );

static jmp_buf alloca_jmp_buf;

LONG WINAPI AllocaExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
{
   
    switch(ExceptionInfo->ExceptionRecord->ExceptionCode) {
        case STATUS_STACK_OVERFLOW :
           
            // reset the stack
            if (0 == _resetstkoflw()) {
                printf("Could not reset the stack!\n");
                _exit(1);
            }
           
            longjmp(alloca_jmp_buf, 1);
           
            break;
    }
   
    return EXCEPTION_EXECUTE_HANDLER;
}

//Alloca survive. Programmed by Carlos Montiers.

int main()
{
    void * m;
    int alloca_jmp_res;
    LPTOP_LEVEL_EXCEPTION_FILTER prev;
   
    //replace the exception filter function saving the previous
    prev = SetUnhandledExceptionFilter(AllocaExceptionFilter);
   
    alloca_jmp_res = setjmp(alloca_jmp_buf);
    if ( (0 == alloca_jmp_res) ) {
        m = alloca( INT_MAX );
       
    } else if ( (1 == alloca_jmp_res) ) {
        m = NULL;
       
    }
   
    //restore exception filter function
    SetUnhandledExceptionFilter(prev);
   
    if (! m) {
        printf("alloca Failed\n");
    }
   
    printf("Bye\n");
    return 1;

}
<div><div dir="ltr">
<div>
<div>Hello.<br>I requesting memory from the stack using the function alloca.<br>
</div>
<div>I know that the use of it is discourage, but I want use it anyways.<br><br>
</div>
<div>I write a code for windows that use it and I tested ok, but only when I compile with gcc. Compiling it with tiny c fails, the program crash.<br>
</div>
<div>Maybe is a bug of tiny c.<br>
</div>
<div>
<br><br>
</div>This is the code:<br><br>#include &lt;windows.h&gt;<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br>#include &lt;limits.h&gt;<br>#include &lt;malloc.h&gt;<br>
#include &lt;setjmp.h&gt;<br><br>int _resetstkoflw ( void );<br><br>static jmp_buf alloca_jmp_buf;<br><br>LONG WINAPI AllocaExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)<br>{<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; switch(ExceptionInfo-&gt;ExceptionRecord-&gt;ExceptionCode) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case STATUS_STACK_OVERFLOW :<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // reset the stack<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (0 == _resetstkoflw()) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("Could not reset the stack!\n");<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _exit(1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; longjmp(alloca_jmp_buf, 1);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; return EXCEPTION_EXECUTE_HANDLER;<br>}<br><br>
</div>//Alloca survive. Programmed by Carlos Montiers.<br><br><div>int main()<br>{<br>&nbsp;&nbsp;&nbsp; void * m;<br>&nbsp;&nbsp;&nbsp; int alloca_jmp_res;<br>&nbsp;&nbsp;&nbsp; LPTOP_LEVEL_EXCEPTION_FILTER prev;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //replace the exception filter function saving the previous<br>&nbsp;&nbsp;&nbsp; prev = SetUnhandledExceptionFilter(AllocaExceptionFilter);<br>
&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; alloca_jmp_res = setjmp(alloca_jmp_buf);<br>&nbsp;&nbsp;&nbsp; if ( (0 == alloca_jmp_res) ) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m = alloca( INT_MAX );<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; } else if ( (1 == alloca_jmp_res) ) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m = NULL;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //restore exception filter function<br>&nbsp;&nbsp;&nbsp; SetUnhandledExceptionFilter(prev);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; if (! m) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("alloca Failed\n");<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; printf("Bye\n");<br>&nbsp;&nbsp;&nbsp; return 1;<br><br>}<br>
</div>
</div></div>
YX Hao | 29 Jun 14:31 2014

Is it a bug or something else?

Hi there,

It is a crash of the complied program, when I played TCC with a small library "http parser"
(https://github.com/joyent/http-parser). And GCC works correctly.

This is out of my knowledge, and I will describe it as clear as possible.

It is about the "test.c".

After some debugging, I find the crash line is calling "test_multiple3()" (L: 3366, L: 3558).

---------------------------------------
  int i, j, k;
  ......
  for (i = 0; i < request_count; i++) {
    if (!requests[i].should_keep_alive) continue;
    for (j = 0; j < request_count; j++) {
      if (!requests[j].should_keep_alive) continue;
      for (k = 0; k < request_count; k++) {
        test_multiple3(&requests[i], &requests[j], &requests[k]);
      }
    }
  }
---------------------------------------

According to a debugger, the program uses a " DWORD PTR SS:[EBP-4]" to store the counters. For example "(i =
0; i < request_count; i++)":

---------------------------------------
CPU Disasm
Address   Hex dump          Command                                  Comments
004055C9  |.  B8 00000000   MOV EAX,0
004055CE  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX             ; i = 0;
004055D1  |>  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
004055D4  |.  8B4D EC       MOV ECX,DWORD PTR SS:[EBP-14]
004055D7  |.  39C8          CMP EAX,ECX
004055D9  |.  0F8D CD000000 JGE 004056AC                             ; if (i > request_count) true;
004055DF  |.  E9 0B000000   JMP 004055EF
004055E4  |>  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
004055E7  |.  89C1          MOV ECX,EAX
004055E9  |.  40            INC EAX                                  ; i++;
004055EA  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX
004055ED  |.^ EB E2         JMP SHORT 004055D1 ---------------------------------------

Entering "test_multiple3()", it stores "EBP" by pushing to stack, and then some operations flush the
stored data, as the routine falls to a label "test". Stange!

---------------------------------------
  if (read != 0) {
    print_error(total, read);
    abort();
  }

test:

  if (message_count != num_messages) {
    fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
    abort();
  }
---------------------------------------

CPU Disasm
Address   Hex dump          Command                                  Comments
0040483A  |> \B8 00000000   MOV EAX,0
0040483F  |.  50            PUSH EAX                                 ; /Arg2 => 0
00404840  |.  B8 00000000   MOV EAX,0                                ; |
00404845  |.  50            PUSH EAX                                 ; |Arg1 => 0
00404846  |.  E8 BED6FFFF   CALL 00401F09                            ; \t.00401F09
0040484B  |.  83C4 08       ADD ESP,8
0040484E  |.  8945 E4       MOV DWORD PTR SS:[LOCAL.7],EAX
00404851  |.  8B45 E4       MOV EAX,DWORD PTR SS:[LOCAL.7]
00404854  |.  83F8 00       CMP EAX,0
00404857  |.  0F84 15000000 JE 00404872
0040485D  |.  8B45 E4       MOV EAX,DWORD PTR SS:[LOCAL.7]
00404860  |.  50            PUSH EAX
00404861  |.  8B45 EC       MOV EAX,DWORD PTR SS:[LOCAL.5]
00404864  |.  50            PUSH EAX
00404865  |.  E8 CAE1FFFF   CALL 00402A34
0040486A  |.  83C4 08       ADD ESP,8
0040486D  |.  E8 96950000   CALL <JMP.&msvcrt.abort>                 ; [MSVCRT.abort
00404872  |>  8965 00       MOV DWORD PTR SS:[LOCAL.0],ESP           ;???
00404875  |>  8B65 00       MOV ESP,DWORD PTR SS:[LOCAL.0]           ;???
00404878  |.  8B45 FC       MOV EAX,DWORD PTR SS:[LOCAL.1]
0040487B  |.  8B0D 44607E00 MOV ECX,DWORD PTR DS:[7E6044]
00404881  |.  39C8          CMP EAX,ECX
00404883  |.  0F84 24000000 JE 004048AD
---------------------------------------

Why are the "???" marked commands there? They flushed the "EBP".

---------------
TCC: latest mob
OS: windows

Attachment is my modified "wassert()" in case of you need it.

Regards,
YX
Attachment (wassert.c): application/octet-stream, 2641 bytes
Hi there,

It is a crash of the complied program, when I played TCC with a small library "http parser"
(https://github.com/joyent/http-parser). And GCC works correctly.

This is out of my knowledge, and I will describe it as clear as possible.

It is about the "test.c".

After some debugging, I find the crash line is calling "test_multiple3()" (L: 3366, L: 3558).

---------------------------------------
  int i, j, k;
  ......
  for (i = 0; i < request_count; i++) {
    if (!requests[i].should_keep_alive) continue;
    for (j = 0; j < request_count; j++) {
      if (!requests[j].should_keep_alive) continue;
      for (k = 0; k < request_count; k++) {
        test_multiple3(&requests[i], &requests[j], &requests[k]);
      }
    }
  }
---------------------------------------

According to a debugger, the program uses a " DWORD PTR SS:[EBP-4]" to store the counters. For example "(i =
0; i < request_count; i++)":

---------------------------------------
CPU Disasm
Address   Hex dump          Command                                  Comments
004055C9  |.  B8 00000000   MOV EAX,0
004055CE  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX             ; i = 0;
004055D1  |>  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
004055D4  |.  8B4D EC       MOV ECX,DWORD PTR SS:[EBP-14]
004055D7  |.  39C8          CMP EAX,ECX
004055D9  |.  0F8D CD000000 JGE 004056AC                             ; if (i > request_count) true;
004055DF  |.  E9 0B000000   JMP 004055EF
004055E4  |>  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
004055E7  |.  89C1          MOV ECX,EAX
004055E9  |.  40            INC EAX                                  ; i++;
004055EA  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX
004055ED  |.^ EB E2         JMP SHORT 004055D1 ---------------------------------------

Entering "test_multiple3()", it stores "EBP" by pushing to stack, and then some operations flush the
stored data, as the routine falls to a label "test". Stange!

---------------------------------------
  if (read != 0) {
    print_error(total, read);
    abort();
  }

test:

  if (message_count != num_messages) {
    fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
    abort();
  }
---------------------------------------

CPU Disasm
Address   Hex dump          Command                                  Comments
0040483A  |> \B8 00000000   MOV EAX,0
0040483F  |.  50            PUSH EAX                                 ; /Arg2 => 0
00404840  |.  B8 00000000   MOV EAX,0                                ; |
00404845  |.  50            PUSH EAX                                 ; |Arg1 => 0
00404846  |.  E8 BED6FFFF   CALL 00401F09                            ; \t.00401F09
0040484B  |.  83C4 08       ADD ESP,8
0040484E  |.  8945 E4       MOV DWORD PTR SS:[LOCAL.7],EAX
00404851  |.  8B45 E4       MOV EAX,DWORD PTR SS:[LOCAL.7]
00404854  |.  83F8 00       CMP EAX,0
00404857  |.  0F84 15000000 JE 00404872
0040485D  |.  8B45 E4       MOV EAX,DWORD PTR SS:[LOCAL.7]
00404860  |.  50            PUSH EAX
00404861  |.  8B45 EC       MOV EAX,DWORD PTR SS:[LOCAL.5]
00404864  |.  50            PUSH EAX
00404865  |.  E8 CAE1FFFF   CALL 00402A34
0040486A  |.  83C4 08       ADD ESP,8
0040486D  |.  E8 96950000   CALL <JMP.&msvcrt.abort>                 ; [MSVCRT.abort
00404872  |>  8965 00       MOV DWORD PTR SS:[LOCAL.0],ESP           ;???
00404875  |>  8B65 00       MOV ESP,DWORD PTR SS:[LOCAL.0]           ;???
00404878  |.  8B45 FC       MOV EAX,DWORD PTR SS:[LOCAL.1]
0040487B  |.  8B0D 44607E00 MOV ECX,DWORD PTR DS:[7E6044]
00404881  |.  39C8          CMP EAX,ECX
00404883  |.  0F84 24000000 JE 004048AD
---------------------------------------

Why are the "???" marked commands there? They flushed the "EBP".

---------------
TCC: latest mob
OS: windows

Attachment is my modified "wassert()" in case of you need it.

Regards,
YX

Gmane