aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/tccgen.c b/tccgen.c
index 8281d1e..70e6fb6 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -575,8 +575,16 @@ static void vsetc(CType *type, int r, CValue *vc)
tcc_error("memory full (vstack)");
/* cannot let cpu flags if other instruction are generated. Also
avoid leaving VT_JMP anywhere except on the top of the stack
- because it would complicate the code generator. */
- if (vtop >= vstack) {
+ because it would complicate the code generator.
+
+ Don't do this when nocode_wanted. vtop might come from
+ !nocode_wanted regions (see 88_codeopt.c) and transforming
+ it to a register without actually generating code is wrong
+ as their value might still be used for real. All values
+ we push under nocode_wanted will eventually be popped
+ again, so that the VT_CMP/VT_JMP value will be in vtop
+ when code is unsuppressed again. */
+ if (vtop >= vstack && !nocode_wanted) {
v = vtop->r & VT_VALMASK;
if (v == VT_CMP || (v & ~1) == VT_JMP)
gv(RC_INT);
@@ -4367,13 +4375,18 @@ ST_FUNC void unary(void)
gen_cast(&type);
}
} else if (tok == '{') {
+ int saved_nocode_wanted = nocode_wanted;
if (const_wanted)
tcc_error("expected constant");
/* save all registers */
save_regs(0);
/* statement expression : we do not accept break/continue
- inside as GCC does */
+ inside as GCC does. We do retain the nocode_wanted state,
+ as statement expressions can't ever be entered from the
+ outside, so any reactivation of code emission (from labels
+ or loop heads) can be disabled again after the end of it. */
block(NULL, NULL, 1);
+ nocode_wanted = saved_nocode_wanted;
skip(')');
} else {
gexpr();