diff --git a/tccgen.c b/tccgen.c index 8b1bcb1..c9d43b4 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5396,7 +5396,8 @@ static void block(int *bsym, int *csym, int is_expr) nocode_wanted |= 2; a = gvtst(1, 0); block(bsym, csym, 0); - nocode_wanted = saved_nocode_wanted; + if (cond != 1) + nocode_wanted = saved_nocode_wanted; c = tok; if (c == TOK_ELSE) { next(); @@ -5406,10 +5407,12 @@ static void block(int *bsym, int *csym, int is_expr) gsym(a); block(bsym, csym, 0); gsym(d); /* patch else jmp */ - nocode_wanted = saved_nocode_wanted; + if (cond != 0) + nocode_wanted = saved_nocode_wanted; } else gsym(a); } else if (tok == TOK_WHILE) { + int saved_nocode_wanted; nocode_wanted &= ~2; next(); d = ind; @@ -5420,7 +5423,9 @@ static void block(int *bsym, int *csym, int is_expr) a = gvtst(1, 0); b = 0; ++local_scope; + saved_nocode_wanted = nocode_wanted; block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; --local_scope; if(!nocode_wanted) gjmp_addr(d); @@ -5556,6 +5561,7 @@ static void block(int *bsym, int *csym, int is_expr) /* jump unless last stmt in top-level block */ if (tok != '}' || local_scope != 1) rsym = gjmp(rsym); + nocode_wanted |= 2; } else if (tok == TOK_BREAK) { /* compute jump */ if (!bsym) @@ -5563,6 +5569,7 @@ static void block(int *bsym, int *csym, int is_expr) *bsym = gjmp(*bsym); next(); skip(';'); + nocode_wanted |= 2; } else if (tok == TOK_CONTINUE) { /* compute jump */ if (!csym) @@ -5573,6 +5580,7 @@ static void block(int *bsym, int *csym, int is_expr) skip(';'); } else if (tok == TOK_FOR) { int e; + int saved_nocode_wanted; nocode_wanted &= ~2; next(); skip('('); @@ -5607,7 +5615,9 @@ static void block(int *bsym, int *csym, int is_expr) gsym(e); } skip(')'); + saved_nocode_wanted = nocode_wanted; block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; if(!nocode_wanted) gjmp_addr(c); gsym(a); @@ -5617,13 +5627,16 @@ static void block(int *bsym, int *csym, int is_expr) } else if (tok == TOK_DO) { + int saved_nocode_wanted; nocode_wanted &= ~2; next(); a = 0; b = 0; d = ind; vla_sp_restore(); + saved_nocode_wanted = nocode_wanted; block(&a, &b, 0); + nocode_wanted = saved_nocode_wanted; skip(TOK_WHILE); skip('('); gsym(b); @@ -5637,6 +5650,7 @@ static void block(int *bsym, int *csym, int is_expr) } else if (tok == TOK_SWITCH) { struct switch_t *saved, sw; + int saved_nocode_wanted = nocode_wanted; next(); skip('('); gexpr(); @@ -5650,6 +5664,7 @@ static void block(int *bsym, int *csym, int is_expr) saved = cur_switch; cur_switch = &sw; block(&a, csym, 0); + nocode_wanted = saved_nocode_wanted; a = gjmp(a); /* add implicit break */ /* case lookup */ gsym(b); diff --git a/tests/tcctest.c b/tests/tcctest.c index 8031af4..a0ddc84 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1184,6 +1184,57 @@ void optimize_out(void) printf("oo:%d\n", defined_function()); else printf("oo:%d\n", undefined_function()); + while (1) { + printf("oow:%d\n", defined_function()); + break; + printf("oow:%d\n", undefined_function()); + } + j = 1; + /* Following is a switch without {} block intentionally. */ + switch (j) + case 1: break; + printf ("oos:%d\n", defined_function()); + /* The following break shouldn't lead to disabled code after + the while. */ + while (1) + break; + printf ("ool1:%d\n", defined_function()); + /* Same for the other types of loops. */ + do + break; + while (1); + printf ("ool2:%d\n", defined_function()); + for (;;) + break; + printf ("ool3:%d\n", defined_function()); + /* Normal {} blocks without controlling statements + shouldn't reactivate code emission */ + while (1) { + { + break; + } + printf ("ool4:%d\n", undefined_function()); + } + j = 1; + while (j) { + if (j == 0) + break; /* this break shouldn't disable code outside the if. */ + printf("ool5:%d\n", defined_function()); + j--; + } + + j = 1; + while (j) { + if (1) + j--; + else + breakhere: break; + printf("ool6:%d\n", defined_function()); + goto breakhere; + } + if (1) + return; + printf ("oor:%d\n", undefined_function()); } int defined_function(void)