diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index d565551ea..9834ae5d1 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -590,6 +590,12 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Normal straight 'op=' */ OpAssignArithmetic (Gen, Expr, Op); } + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -710,4 +716,10 @@ void OpAddSubAssign (const GenDesc* Gen, ExprDesc *Expr, const char* Op) /* Expression is an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 506a963a6..ef3c4ec38 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -642,6 +642,9 @@ void DoDeferred (unsigned Flags, ExprDesc* Expr) /* Sufficient to pop the processor flags */ AddCodeLine ("plp"); } + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -816,6 +819,9 @@ static unsigned FunctionArgList (FuncDesc* Func, int IsFastcall, ExprDesc* ED) } } + /* Propagate viral flags */ + ED_PropagateFrom (ED, &Expr); + /* Check for end of argument list */ if (CurTok.Tok != TOK_COMMA) { break; @@ -1058,6 +1064,9 @@ static void FunctionCall (ExprDesc* Expr) } Expr->Type = ReturnType; + + /* We assume all function calls had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1267,7 +1276,7 @@ static void Primary (ExprDesc* E) case TOK_ASM: /* ASM statement */ AsmStatement (); - E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED; + E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED | E_SIDE_EFFECTS; E->Type = type_void; break; @@ -1652,6 +1661,9 @@ static void PreInc (ExprDesc* Expr) /* Result is an expression, no reference */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1679,6 +1691,9 @@ static void PreDec (ExprDesc* Expr) /* Result is an expression, no reference */ ED_FinalizeRValLoad (Expr); + + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; } @@ -1715,6 +1730,9 @@ static void PostInc (ExprDesc* Expr) LoadExpr (CF_NONE, Expr); AddCodeLine ("inc %s", ED_GetLabelName (Expr, 0)); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { if (ED_IsLocPrimaryOrExpr (Expr)) { @@ -1722,6 +1740,9 @@ static void PostInc (ExprDesc* Expr) /* Do the increment */ DoInc (Expr, OA_NEED_OLD); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { /* Defer the increment until after the value of this expression is used */ @@ -1765,6 +1786,9 @@ static void PostDec (ExprDesc* Expr) LoadExpr (CF_NONE, Expr); AddCodeLine ("dec %s", ED_GetLabelName (Expr, 0)); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { if (ED_IsLocPrimaryOrExpr (Expr)) { @@ -1772,6 +1796,9 @@ static void PostDec (ExprDesc* Expr) /* Do the decrement */ DoDec (Expr, OA_NEED_OLD); + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } else { /* Defer the decrement until after the value of this expression is used */ @@ -2232,6 +2259,9 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* We have an rvalue in the primary now */ ED_FinalizeRValLoad (Expr); } + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } } @@ -2653,6 +2683,9 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Result type is always boolean */ Done: Expr->Type = type_bool; + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } } @@ -3069,6 +3102,9 @@ static void parseadd (ExprDesc* Expr, int DoArrayRef) /* Condition code not set */ ED_MarkAsUntested (Expr); + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -3346,6 +3382,9 @@ static void parsesub (ExprDesc* Expr) /* Condition code not set */ ED_MarkAsUntested (Expr); + + /* Propagate viral flags */ + ED_PropagateFrom (Expr, &Expr2); } @@ -3597,6 +3636,12 @@ static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated) } } } + + /* Propagate viral flags */ + if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + } /* Last expression */ @@ -3762,6 +3807,11 @@ static void hieOr (ExprDesc *Expr) } } + /* Propagate viral flags */ + if ((Expr->Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + } /* Convert to bool */ @@ -4053,6 +4103,14 @@ static void hieQuest (ExprDesc* Expr) /* Setup the target expression */ Expr->Type = ResultType; + + /* Propagate viral flags */ + if ((Expr2.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr2); + } + if ((Expr3.Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) { + ED_PropagateFrom (Expr, &Expr3); + } } } @@ -4134,22 +4192,29 @@ void hie0 (ExprDesc *Expr) ** emit a warning. */ GetCodePos (&End); - if (!ED_MayHaveNoEffect (Expr) && - CodeRangeIsEmpty (&Start, &End) && - IS_Get (&WarnNoEffect) && + if (!ED_MayHaveNoEffect (Expr) && + (CodeRangeIsEmpty (&Start, &End) || + (Expr->Flags & E_SIDE_EFFECTS) == 0) && + IS_Get (&WarnNoEffect) && PrevErrorCount == ErrorCount) { - Warning ("Expression result unused"); + Warning ("Left-hand operand of comma expression has no effect"); } PrevErrorCount = ErrorCount; /* Remember the current code position */ GetCodePos (&Start); + /* Keep viral flags propagated from subexpressions */ + Flags |= Expr->Flags & E_MASK_VIRAL; + /* Reset the expression */ ED_Init (Expr); - Expr->Flags = Flags; + Expr->Flags = Flags & ~E_MASK_VIRAL; NextToken (); hie1 (Expr); + + /* Propagate viral flags */ + Expr->Flags |= Flags & E_MASK_VIRAL; } } diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index f2b66ee56..a1674a7cc 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -125,6 +125,7 @@ enum { E_LOADED = 0x1000, /* Expression is loaded in primary */ E_CC_SET = 0x2000, /* Condition codes are set */ E_HAVE_MARKS = 0x4000, /* Code marks are valid */ + E_SIDE_EFFECTS = 0x8000, /* Expression has had side effects */ /* Optimization hints */ E_MASK_NEED = 0x030000, @@ -181,6 +182,9 @@ enum { /* Expression result must be known to the compiler and generate no code to load */ E_EVAL_C_CONST = E_EVAL_COMPILER_KNOWN | E_EVAL_NO_CODE, + /* Flags to combine from subexpressions */ + E_MASK_VIRAL = E_SIDE_EFFECTS, + /* Flags to keep in subexpressions of most operations other than ternary */ E_MASK_KEEP_SUBEXPR = E_MASK_EVAL, @@ -467,6 +471,16 @@ INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr) # define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED) #endif +#if defined(HAVE_INLINE) +INLINE void ED_PropagateFrom (ExprDesc* Expr, const ExprDesc* SubExpr) +/* Propagate viral flags from subexpression */ +{ + Expr->Flags |= SubExpr->Flags & E_MASK_VIRAL; +} +#else +# define ED_PropagateFrom(Expr, SubExpr) (void)((Expr)->Flags |= (SubExpr)->Flags & E_MASK_VIRAL) +#endif + #if defined(HAVE_INLINE) INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr) /* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */ diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index c5badc1b3..0b75e0a9c 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -278,4 +278,8 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) } } + if (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)) { + /* Expression has had side effects */ + Expr->Flags |= E_SIDE_EFFECTS; + } } diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index f7385ace1..eb879a475 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -237,5 +237,8 @@ MakeRVal: /* Set the type of the result */ Expr->Type = ResultType; + + /* Propagate from subexpressions */ + Expr->Flags |= Expr2.Flags & E_MASK_VIRAL; } } diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 37566a455..5ed5ce671 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -185,6 +185,9 @@ static void ParseArg (ArgDesc* Arg, const Type* Type, ExprDesc* Expr) /* Use the type of the argument for the push */ Arg->Flags |= TypeOf (Arg->Expr.Type); + + /* Propagate from subexpressions */ + Expr->Flags |= Arg->Expr.Flags & E_MASK_VIRAL; } @@ -1365,6 +1368,9 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ExitPoint: /* We expect the closing brace */ ConsumeRParen (); + + /* Propagate from subexpressions */ + Expr->Flags |= Arg.Flags & E_MASK_VIRAL; } @@ -1405,4 +1411,7 @@ void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval) /* Call the handler function */ D->Handler (F, lval); + + /* We assume all function calls had side effects */ + lval->Flags |= E_SIDE_EFFECTS; } diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 022a8475c..a08197c09 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -613,12 +613,13 @@ static void Statement (int* PendingToken) ** void, emit a warning. */ GetCodePos (&End); - if (!ED_YetToLoad (&Expr) && - !ED_MayHaveNoEffect (&Expr) && - CodeRangeIsEmpty (&Start, &End) && - IS_Get (&WarnNoEffect) && + if (!ED_YetToLoad (&Expr) && + !ED_MayHaveNoEffect (&Expr) && + (CodeRangeIsEmpty (&Start, &End) || + (Expr.Flags & E_SIDE_EFFECTS) == 0) && + IS_Get (&WarnNoEffect) && PrevErrorCount == ErrorCount) { - Warning ("Expression result unused"); + Warning ("Statement has no effect"); } CheckSemi (PendingToken); }