diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index ae4308522..20de6033e 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -132,6 +132,8 @@ static void ParseByteArg (StrBuf* T, unsigned Arg) ExprDesc Expr; char Buf [16]; + ED_Init (&Expr); + /* We expect an argument separated by a comma */ ConsumeComma (); @@ -166,6 +168,8 @@ static void ParseWordArg (StrBuf* T, unsigned Arg) ExprDesc Expr; char Buf [16]; + ED_Init (&Expr); + /* We expect an argument separated by a comma */ ConsumeComma (); @@ -200,6 +204,8 @@ static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused))) ExprDesc Expr; char Buf [16]; + ED_Init (&Expr); + /* We expect an argument separated by a comma */ ConsumeComma (); @@ -309,6 +315,8 @@ static void ParseStrArg (StrBuf* T, unsigned Arg attribute ((unused))) ExprDesc Expr; char Buf [64]; + ED_Init (&Expr); + /* We expect an argument separated by a comma */ ConsumeComma (); diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index 6acab3fe8..71df0c4f2 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -139,6 +139,7 @@ void Assignment (ExprDesc* Expr) ExprDesc Expr2; Type* ltype = Expr->Type; + ED_Init (&Expr2); /* We must have an lvalue for an assignment */ if (ED_IsRVal (Expr)) { diff --git a/src/cc65/declare.c b/src/cc65/declare.c index ccd4e9004..7e5f24b24 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -591,6 +591,7 @@ static SymEntry* ParseEnumDecl (const char* Name) if (CurTok.Tok == TOK_ASSIGN) { ExprDesc Expr; + ED_Init (&Expr); NextToken (); ConstAbsIntExpr (hie1, &Expr); EnumVal = Expr.IVal; @@ -720,6 +721,7 @@ static int ParseFieldWidth (Declaration* Decl) */ { ExprDesc Expr; + ED_Init (&Expr); if (CurTok.Tok != TOK_COLON) { /* No bit-field declaration */ @@ -1818,6 +1820,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode) /* Read the size if it is given */ if (CurTok.Tok != TOK_RBRACK) { ExprDesc Expr; + ED_Init (&Expr); ConstAbsIntExpr (hie1, &Expr); if (Expr.IVal <= 0) { if (D->Ident[0] != '\0') { @@ -2184,6 +2187,7 @@ static unsigned ParseScalarInit (Type* T) /* Parse initializaton for scalar data types. Return the number of data bytes. */ { ExprDesc ED; + ED_Init (&ED); /* Parse initialization */ ParseScalarInitInternal (T, &ED); @@ -2205,6 +2209,8 @@ static unsigned ParsePointerInit (Type* T) /* Expression */ ExprDesc ED; + ED_Init (&ED); + ConstExpr (hie1, &ED); TypeConversion (&ED, T); @@ -2420,6 +2426,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers) ** handling. */ ExprDesc ED; + ED_Init (&ED); unsigned Val; unsigned Shift; @@ -2541,7 +2548,6 @@ static unsigned ParseVoidInit (Type* T) ** Return the number of bytes initialized. */ { - ExprDesc Expr; unsigned Size; /* Opening brace */ @@ -2550,6 +2556,9 @@ static unsigned ParseVoidInit (Type* T) /* Allow an arbitrary list of values */ Size = 0; do { + ExprDesc Expr; + ED_Init (&Expr); + ConstExpr (hie1, &Expr); switch (GetUnderlyingTypeCode (&Expr.Type[0])) { diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 3d4a5eb1b..62136e122 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -311,13 +311,15 @@ void PushAddr (const ExprDesc* Expr) -static void WarnConstCompareResult (void) +static void WarnConstCompareResult (const ExprDesc* Expr) /* If the result of a comparison is constant, this is suspicious when not in ** preprocessor mode. */ { - if (!Preprocessing && IS_Get (&WarnConstComparison) != 0) { - Warning ("Result of comparison is constant"); + if (!Preprocessing && + !ED_NeedsConst (Expr) && + IS_Get (&WarnConstComparison) != 0) { + Warning ("Result of comparison is always %s", Expr->IVal != 0 ? "true" : "false"); } } @@ -387,6 +389,7 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) unsigned Flags; ExprDesc Expr; + ED_Init (&Expr); /* Count arguments */ ++PushedCount; @@ -727,23 +730,20 @@ static void Primary (ExprDesc* E) { SymEntry* Sym; - /* Initialize fields in the expression stucture */ - ED_Init (E); - /* Character and integer constants. */ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { - E->IVal = CurTok.IVal; - E->Flags = E_LOC_NONE | E_RTYPE_RVAL; - E->Type = CurTok.Type; + E->IVal = CurTok.IVal; + E->Flags |= E_LOC_NONE | E_RTYPE_RVAL; + E->Type = CurTok.Type; NextToken (); return; } /* Floating point constant */ if (CurTok.Tok == TOK_FCONST) { - E->FVal = CurTok.FVal; - E->Flags = E_LOC_NONE | E_RTYPE_RVAL; - E->Type = CurTok.Type; + E->FVal = CurTok.FVal; + E->Flags |= E_LOC_NONE | E_RTYPE_RVAL; + E->Type = CurTok.Type; NextToken (); return; } @@ -777,6 +777,8 @@ static void Primary (ExprDesc* E) return; } + unsigned Flags = E->Flags & E_MASK_KEEP_MAKE; + switch (CurTok.Tok) { case TOK_BOOL_AND: @@ -812,8 +814,8 @@ static void Primary (ExprDesc* E) /* Cannot use type symbols */ Error ("Variable identifier expected"); /* Assume an int type to make E valid */ - E->Flags = E_LOC_STACK | E_RTYPE_LVAL; - E->Type = type_int; + E->Flags |= E_LOC_STACK | E_RTYPE_LVAL; + E->Type = type_int; return; } @@ -924,7 +926,7 @@ static void Primary (ExprDesc* E) case TOK_ASM: /* ASM statement */ AsmStatement (); - E->Flags = E_RTYPE_RVAL; + E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED; E->Type = type_void; break; @@ -985,6 +987,8 @@ static void Primary (ExprDesc* E) ED_MakeConstAbsInt (E, 1); break; } + + E->Flags |= Flags; } @@ -1000,6 +1004,8 @@ static void ArrayRef (ExprDesc* Expr) Type* ElementType; Type* tptr1; + ED_Init (&Subscript); + Subscript.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; /* Skip the bracket */ NextToken (); @@ -2029,7 +2035,6 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ int* UsedGen) /* Helper function */ { - ExprDesc Expr2; CodeMark Mark1; CodeMark Mark2; const GenDesc* Gen; @@ -2044,6 +2049,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ *UsedGen = 0; while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { + ExprDesc Expr2; + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; + /* Tell the caller that we handled it's ops */ *UsedGen = 1; @@ -2248,7 +2257,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ void (*hienext) (ExprDesc*)) /* Helper function for the compare operators */ { - ExprDesc Expr2; CodeMark Mark0; CodeMark Mark1; CodeMark Mark2; @@ -2263,6 +2271,10 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { + ExprDesc Expr2; + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; + /* Remember the generator function */ void (*GenFunc) (unsigned, unsigned long) = Gen->Func; @@ -2362,11 +2374,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Check for const operands */ if (ED_IsConstAbs (Expr) && rconst) { - /* If the result is constant, this is suspicious when not in - ** preprocessor mode. - */ - WarnConstCompareResult (); - /* Both operands are constant, remove the generated code */ RemoveCode (&Mark1); @@ -2403,6 +2410,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } } + /* If the result is constant, this is suspicious when not in + ** preprocessor mode. + */ + WarnConstCompareResult (Expr); + } else { /* Determine the signedness of the operands */ @@ -2461,7 +2473,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_EQ: if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { ED_MakeConstAbsInt (Expr, 0); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2469,7 +2481,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_NE: if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { ED_MakeConstAbsInt (Expr, 1); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2477,7 +2489,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_LT: if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2485,7 +2497,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_LE: if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2493,7 +2505,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_GE: if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2501,7 +2513,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ case TOK_GT: if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin); - WarnConstCompareResult (); + WarnConstCompareResult (Expr); goto Done; } break; @@ -2635,6 +2647,9 @@ static void parseadd (ExprDesc* Expr) Type* lhst; /* Type of left hand side */ Type* rhst; /* Type of right hand side */ + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; + /* Skip the PLUS token */ NextToken (); @@ -2869,6 +2884,8 @@ static void parsesub (ExprDesc* Expr) CodeMark Mark2; /* Another position in the queue */ int rscale; /* Scale factor for the result */ + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; /* lhs cannot be function or pointer to function */ if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) { @@ -3130,11 +3147,12 @@ static void hieAndPP (ExprDesc* Expr) ** called recursively from the preprocessor. */ { - ExprDesc Expr2; - ConstAbsIntExpr (hie2, Expr); while (CurTok.Tok == TOK_BOOL_AND) { + ExprDesc Expr2; + ED_Init (&Expr2); + /* Skip the && */ NextToken (); @@ -3153,11 +3171,12 @@ static void hieOrPP (ExprDesc *Expr) ** called recursively from the preprocessor. */ { - ExprDesc Expr2; - ConstAbsIntExpr (hieAndPP, Expr); while (CurTok.Tok == TOK_BOOL_OR) { + ExprDesc Expr2; + ED_Init (&Expr2); + /* Skip the && */ NextToken (); @@ -3175,8 +3194,6 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Process "exp && exp" */ { int FalseLab; - ExprDesc Expr2; - ExprWithCheck (hie2, Expr); if (CurTok.Tok == TOK_BOOL_AND) { @@ -3186,10 +3203,8 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Get a label that we will use for false expressions */ FalseLab = GetLocalLabel (); - /* If the expr hasn't set condition codes, set the force-test flag */ - if (!ED_IsTested (Expr)) { - ED_MarkForTest (Expr); - } + /* Set the test flag */ + ED_RequireTest (Expr); /* Load the value */ LoadExpr (CF_FORCECHAR, Expr); @@ -3200,14 +3215,15 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Parse more boolean and's */ while (CurTok.Tok == TOK_BOOL_AND) { + ExprDesc Expr2; + ED_Init (&Expr2); + /* Skip the && */ NextToken (); /* Get rhs */ hie2 (&Expr2); - if (!ED_IsTested (&Expr2)) { - ED_MarkForTest (&Expr2); - } + ED_RequireTest (&Expr2); LoadExpr (CF_FORCECHAR, &Expr2); /* Do short circuit evaluation */ @@ -3233,7 +3249,6 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) static void hieOr (ExprDesc *Expr) /* Process "exp || exp". */ { - ExprDesc Expr2; int BoolOp = 0; /* Did we have a boolean op? */ int AndOp; /* Did we have a && operation? */ unsigned TrueLab; /* Jump to this label if true */ @@ -3248,10 +3263,8 @@ static void hieOr (ExprDesc *Expr) /* Any boolean or's? */ if (CurTok.Tok == TOK_BOOL_OR) { - /* If the expr hasn't set condition codes, set the force-test flag */ - if (!ED_IsTested (Expr)) { - ED_MarkForTest (Expr); - } + /* Set the test flag */ + ED_RequireTest (Expr); /* Get first expr */ LoadExpr (CF_FORCECHAR, Expr); @@ -3269,15 +3282,16 @@ static void hieOr (ExprDesc *Expr) /* while there's more expr */ while (CurTok.Tok == TOK_BOOL_OR) { + ExprDesc Expr2; + ED_Init (&Expr2); + /* skip the || */ NextToken (); /* Get a subexpr */ AndOp = 0; hieAnd (&Expr2, TrueLab, &AndOp); - if (!ED_IsTested (&Expr2)) { - ED_MarkForTest (&Expr2); - } + ED_RequireTest (&Expr2); LoadExpr (CF_FORCECHAR, &Expr2); /* If there is more to come, add shortcut boolean eval. */ @@ -3308,6 +3322,7 @@ static void hieQuest (ExprDesc* Expr) { int FalseLab; int TrueLab; + CodeMark SkippedBranch; CodeMark TrueCodeEnd; ExprDesc Expr2; /* Expression 2 */ ExprDesc Expr3; /* Expression 3 */ @@ -3315,6 +3330,10 @@ static void hieQuest (ExprDesc* Expr) int Expr3IsNULL; /* Expression 3 is a NULL pointer */ Type* ResultType; /* Type of result */ + ED_Init (&Expr2); + Expr2.Flags = Expr->Flags & E_MASK_KEEP_RESULT; + ED_Init (&Expr3); + Expr3.Flags = Expr->Flags & E_MASK_KEEP_RESULT; /* Call the lower level eval routine */ if (Preprocessing) { @@ -3325,14 +3344,20 @@ static void hieQuest (ExprDesc* Expr) /* Check if it's a ternary expression */ if (CurTok.Tok == TOK_QUEST) { + + int ConstantCond = ED_IsConstAbsInt (Expr); NextToken (); - if (!ED_IsTested (Expr)) { + + if (!ConstantCond) { /* Condition codes not set, request a test */ - ED_MarkForTest (Expr); + ED_RequireTest (Expr); + LoadExpr (CF_NONE, Expr); + FalseLab = GetLocalLabel (); + g_falsejump (CF_NONE, FalseLab); + } else if (Expr->IVal == 0) { + /* Remember the current code position */ + GetCodePos (&SkippedBranch); } - LoadExpr (CF_NONE, Expr); - FalseLab = GetLocalLabel (); - g_falsejump (CF_NONE, FalseLab); /* Parse second expression. Remember for later if it is a NULL pointer ** expression, then load it into the primary. @@ -3340,22 +3365,37 @@ static void hieQuest (ExprDesc* Expr) ExprWithCheck (hie1, &Expr2); Expr2IsNULL = ED_IsNullPtr (&Expr2); if (!IsTypeVoid (Expr2.Type)) { - /* Load it into the primary */ - LoadExpr (CF_NONE, &Expr2); - ED_FinalizeRValLoad (&Expr2); + if (!ConstantCond || !ED_IsConst (&Expr2)) { + /* Load it into the primary */ + LoadExpr (CF_NONE, &Expr2); + ED_FinalizeRValLoad (&Expr2); + } Expr2.Type = PtrConversion (Expr2.Type); } - /* Remember the current code position */ - GetCodePos (&TrueCodeEnd); + if (!ConstantCond) { + /* Remember the current code position */ + GetCodePos (&TrueCodeEnd); - /* Jump around the evaluation of the third expression */ - TrueLab = GetLocalLabel (); - ConsumeColon (); - g_jump (TrueLab); + /* Jump around the evaluation of the third expression */ + TrueLab = GetLocalLabel (); - /* Jump here if the first expression was false */ - g_defcodelabel (FalseLab); + ConsumeColon (); + + g_jump (TrueLab); + + /* Jump here if the first expression was false */ + g_defcodelabel (FalseLab); + } else { + if (Expr->IVal == 0) { + /* Remove the load code of Expr2 */ + RemoveCode (&SkippedBranch); + } else { + /* Remember the current code position */ + GetCodePos (&SkippedBranch); + } + ConsumeColon(); + } /* Parse third expression. Remember for later if it is a NULL pointer ** expression, then load it into the primary. @@ -3363,12 +3403,19 @@ static void hieQuest (ExprDesc* Expr) ExprWithCheck (hie1, &Expr3); Expr3IsNULL = ED_IsNullPtr (&Expr3); if (!IsTypeVoid (Expr3.Type)) { - /* Load it into the primary */ - LoadExpr (CF_NONE, &Expr3); - ED_FinalizeRValLoad (&Expr3); + if (!ConstantCond || !ED_IsConst (&Expr3)) { + /* Load it into the primary */ + LoadExpr (CF_NONE, &Expr3); + ED_FinalizeRValLoad (&Expr3); + } Expr3.Type = PtrConversion (Expr3.Type); } + if (ConstantCond && Expr->IVal != 0) { + /* Remove the load code of Expr3 */ + RemoveCode (&SkippedBranch); + } + /* Check if any conversions are needed, if so, do them. ** Conversion rules for ?: expression are: ** - if both expressions are int expressions, default promotion @@ -3401,9 +3448,11 @@ static void hieQuest (ExprDesc* Expr) TypeConversion (&Expr2, ResultType); GetCodePos (&CvtCodeEnd); - /* If we had conversion code, move it to the right place */ - if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) { - MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd); + if (!ConstantCond) { + /* If we had conversion code, move it to the right place */ + if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) { + MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd); + } } } else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) { @@ -3423,16 +3472,30 @@ static void hieQuest (ExprDesc* Expr) /* Result type is void */ ResultType = Expr3.Type; } else { - TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1, - "Incompatible types in ternary '%s' with '%s'"); - ResultType = Expr2.Type; /* Doesn't matter here */ + if (IsClassStruct (Expr2.Type) && IsClassStruct (Expr3.Type) && + TypeCmp (Expr2.Type, Expr3.Type) == TC_IDENTICAL) { + /* Result type is struct/union */ + ResultType = Expr2.Type; + } else { + TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1, + "Incompatible types in ternary '%s' with '%s'"); + ResultType = Expr2.Type; /* Doesn't matter here */ + } } - /* Define the final label */ - g_defcodelabel (TrueLab); + if (!ConstantCond) { + /* Define the final label */ + g_defcodelabel (TrueLab); + ED_FinalizeRValLoad (Expr); + } else { + if (Expr->IVal != 0) { + *Expr = Expr2; + } else { + *Expr = Expr3; + } + } /* Setup the target expression */ - ED_FinalizeRValLoad (Expr); Expr->Type = ResultType; } } @@ -3442,7 +3505,6 @@ static void hieQuest (ExprDesc* Expr) static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Process "op=" operators. */ { - ExprDesc Expr2; unsigned flags; CodeMark Mark; int MustScale; @@ -3483,6 +3545,10 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) GetCodePos (&Mark); g_push (flags, 0); + ExprDesc Expr2; + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; + /* Evaluate the rhs */ MarkedExprWithCheck (hie1, &Expr2); @@ -3563,6 +3629,8 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) unsigned rflags; int MustScale; + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; /* We're currently only able to handle some addressing modes */ if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) { @@ -3756,8 +3824,33 @@ void hie1 (ExprDesc* Expr) void hie0 (ExprDesc *Expr) /* Parse comma operator. */ { + unsigned Flags = Expr->Flags & E_MASK_KEEP_MAKE; + unsigned PrevErrorCount = ErrorCount; + CodeMark Start, End; + + /* Remember the current code position */ + GetCodePos (&Start); + hie1 (Expr); while (CurTok.Tok == TOK_COMMA) { + /* If the expression didn't generate code or isn't cast to type void, + ** emit a warning. + */ + GetCodePos (&End); + if (!ED_MayHaveNoEffect (Expr) && + CodeRangeIsEmpty (&Start, &End) && + IS_Get (&WarnNoEffect) && + PrevErrorCount == ErrorCount) { + Warning ("Expression result unused"); + } + + PrevErrorCount = ErrorCount; + /* Remember the current code position */ + GetCodePos (&Start); + + /* Reset the expression */ + ED_Init (Expr); + Expr->Flags = Flags; NextToken (); hie1 (Expr); } @@ -3791,8 +3884,18 @@ int evalexpr (unsigned Flags, void (*Func) (ExprDesc*), ExprDesc* Expr) void Expression0 (ExprDesc* Expr) /* Evaluate an expression via hie0 and put the result into the primary register */ { + unsigned Flags = Expr->Flags & E_MASK_KEEP_RESULT; + + /* Only check further after the expression is evaluated */ ExprWithCheck (hie0, Expr); - LoadExpr (CF_NONE, Expr); + + if ((Expr->Flags & Flags & E_MASK_EVAL) != (Flags & E_MASK_EVAL)) { + Internal ("Expression flags tampered: %08X", Flags); + } + + if (ED_YetToLoad (Expr)) { + LoadExpr (CF_NONE, Expr); + } } @@ -3804,6 +3907,7 @@ void ConstExpr (void (*Func) (ExprDesc*), ExprDesc* Expr) ** result from this input error. */ { + Expr->Flags |= E_EVAL_CONST; ExprWithCheck (Func, Expr); if (!ED_IsConst (Expr)) { Error ("Constant expression expected"); @@ -3838,6 +3942,7 @@ void ConstAbsIntExpr (void (*Func) (ExprDesc*), ExprDesc* Expr) ** errors that result from this input error. */ { + Expr->Flags |= E_EVAL_CONST; ExprWithCheck (Func, Expr); if (!ED_IsConstAbsInt (Expr)) { Error ("Constant integer expression expected"); diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index d0ee2789a..c3f4c63f7 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -58,7 +58,7 @@ ExprDesc* ED_Init (ExprDesc* Expr) { Expr->Sym = 0; Expr->Type = 0; - Expr->Flags = 0; + Expr->Flags = E_NEED_EAX; Expr->Name = 0; Expr->IVal = 0; Expr->FVal = FP_D_Make (0.0); @@ -113,6 +113,24 @@ int ED_IsIndExpr (const ExprDesc* Expr) +int ED_YetToLoad (const ExprDesc* Expr) +/* Check if the expression needs to be loaded somehow. */ +{ + return ED_NeedsPrimary (Expr) || + ED_YetToTest (Expr) || + (ED_IsLVal (Expr) && IsQualVolatile (Expr->Type)); +} + + + +void ED_MarkForUneval (ExprDesc* Expr) +/* Mark the expression as not to be evaluated */ +{ + Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL; +} + + + void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End) /* Set the code range for this expression */ { @@ -206,7 +224,7 @@ ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type) { Expr->Sym = 0; Expr->Type = Type; - Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); + Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE); Expr->Name = 0; Expr->IVal = Value; Expr->FVal = FP_D_Make (0.0); @@ -220,7 +238,7 @@ ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value) { Expr->Sym = 0; Expr->Type = type_int; - Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS); + Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE); Expr->Name = 0; Expr->IVal = Value; Expr->FVal = FP_D_Make (0.0); @@ -412,7 +430,8 @@ int ED_IsBool (const ExprDesc* Expr) /* Either ints, floats, or pointers can be used in a boolean context */ return IsClassInt (Expr->Type) || IsClassFloat (Expr->Type) || - IsClassPtr (Expr->Type); + IsClassPtr (Expr->Type) || + IsClassFunc (Expr->Type); } diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index 0a0f970a6..68db8b2fe 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -94,7 +94,7 @@ enum { ** E_LOC_ -- dereference -> E_LOC_EXPR (pointed-to-value, must load) ** + E_ADDRESS_OF -- dereference -> (lvalue reference) */ - E_MASK_LOC = 0x00FF, + E_MASK_LOC = 0x01FF, E_LOC_NONE = 0x0000, /* Pure rvalue with no storage */ E_LOC_ABS = 0x0001, /* Absolute numeric addressed variable */ E_LOC_GLOBAL = 0x0002, /* Global variable */ @@ -104,29 +104,58 @@ enum { E_LOC_PRIMARY = 0x0020, /* Temporary in primary register */ E_LOC_EXPR = 0x0040, /* A location that the primary register points to */ E_LOC_LITERAL = 0x0080, /* Literal in the literal pool */ + E_LOC_CODE = 0x0100, /* C code label location (&&Label) */ - /* Constant location of some sort (only if rval) */ + /* Immutable location addresses (immutable bases and offsets) */ E_LOC_CONST = E_LOC_NONE | E_LOC_ABS | E_LOC_GLOBAL | E_LOC_STATIC | - E_LOC_REGISTER | E_LOC_LITERAL, + E_LOC_REGISTER | E_LOC_LITERAL | E_LOC_CODE, + + /* Not-so-immutable location addresses (stack offsets can change) */ + E_LOC_QUASICONST = E_LOC_CONST | E_LOC_STACK, + + /* Expression type modifiers */ + E_BITFIELD = 0x0200, /* Expression is a bit-field */ + E_ADDRESS_OF = 0x0400, /* Expression is the address of the lvalue */ /* lvalue/rvalue in C language's sense */ - E_MASK_RTYPE = 0x0100, + E_MASK_RTYPE = 0x0800, E_RTYPE_RVAL = 0x0000, - E_RTYPE_LVAL = 0x0100, + E_RTYPE_LVAL = 0x0800, - /* Bit-field? */ - E_BITFIELD = 0x0200, + /* Expression status */ + E_LOADED = 0x1000, /* Expression is loaded in primary */ + E_CC_SET = 0x2000, /* Condition codes are set */ + E_HAVE_MARKS = 0x4000, /* Code marks are valid */ - /* Test */ - E_NEED_TEST = 0x0400, /* Expression needs a test to set cc */ - E_CC_SET = 0x0800, /* Condition codes are set */ + /* Optimization hints */ + E_MASK_NEED = 0x030000, + E_NEED_EAX = 0x000000, /* Expression needs to be loaded in Primary */ + E_NEED_NONE = 0x010000, /* Expression value is unused */ + E_NEED_TEST = 0x020000, /* Expression needs a test to set cc */ - E_HAVE_MARKS = 0x1000, /* Code marks are valid */ + /* Expression evaluation requirements. + ** Usage: (Flags & E_EVAL_) == E_EVAL_ + */ + E_MASK_EVAL = 0xFC0000, + E_EVAL_NONE = 0x000000, /* No requirements */ + E_EVAL_CONST = 0x040000, /* Result must be immutable */ + E_EVAL_COMPILE_TIME = 0x0C0000, /* Result must be known at compile time */ + E_EVAL_PURE = 0x100000, /* Evaluation must have no side effects */ + E_EVAL_STATIC = 0x340000, /* Evaluation must generate no code */ + E_EVAL_MAYBE_UNUSED = 0x400000, /* Result may be unused */ + E_EVAL_UNEVAL = 0xC00000, /* Expression is unevaluated */ - E_LOADED = 0x4000, /* Expression is loaded in primary */ + /* Expression must be static and have result known at compile time */ + E_EVAL_C_CONST = E_EVAL_COMPILE_TIME | E_EVAL_STATIC, - E_ADDRESS_OF = 0x8000, /* Expression is the address of the lvalue */ + /* Flags to keep in subexpressions */ + E_MASK_KEEP_SUBEXPR = E_MASK_EVAL, + /* Flags to keep in ternary subexpressions */ + E_MASK_KEEP_RESULT = E_MASK_NEED | E_MASK_EVAL, + + /* Flags to keep when using the ED_Make functions */ + E_MASK_KEEP_MAKE = E_HAVE_MARKS | E_MASK_KEEP_RESULT, }; /* Forward */ @@ -292,13 +321,33 @@ void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth); /* Make this expression a bit field expression */ #if defined(HAVE_INLINE) -INLINE void ED_MarkForTest (ExprDesc* Expr) +INLINE void ED_RequireTest (ExprDesc* Expr) /* Mark the expression for a test. */ { Expr->Flags |= E_NEED_TEST; } #else -# define ED_MarkForTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0) +# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0) +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_GetNeeds (const ExprDesc* Expr) +/* Get flags about what the expression needs. */ +{ + return (Expr->Flags & E_MASK_NEED); +} +#else +# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED) +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_NeedsPrimary (const ExprDesc* Expr) +/* Check if the expression needs to be in Primary. */ +{ + return (Expr->Flags & E_MASK_NEED) == E_NEED_EAX; +} +#else +# define ED_NeedsPrimary(Expr) (((Expr)->Flags & E_MASK_NEED) == E_NEED_EAX) #endif #if defined(HAVE_INLINE) @@ -311,15 +360,25 @@ INLINE int ED_NeedsTest (const ExprDesc* Expr) # define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0) #endif +#if defined(HAVE_INLINE) +INLINE int ED_YetToTest (const ExprDesc* Expr) +/* Check if the expression needs to be tested but not yet. */ +{ + return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST; +} +#else +# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST) +#endif + #if defined(HAVE_INLINE) INLINE void ED_TestDone (ExprDesc* Expr) /* Mark the expression as tested and condition codes set. */ { - Expr->Flags = (Expr->Flags & ~E_NEED_TEST) | E_CC_SET; + Expr->Flags |= E_CC_SET; } #else # define ED_TestDone(Expr) \ - do { (Expr)->Flags = ((Expr)->Flags & ~E_NEED_TEST) | E_CC_SET; } while (0) + do { (Expr)->Flags |= E_CC_SET; } while (0) #endif #if defined(HAVE_INLINE) @@ -354,6 +413,42 @@ INLINE int ED_IsLoaded (const ExprDesc* Expr) # define ED_IsLoaded(Expr) (((Expr)->Flags & E_LOADED) != 0) #endif +int ED_YetToLoad (const ExprDesc* Expr); +/* Check if the expression is yet to be loaded somehow. */ + +#if defined(HAVE_INLINE) +INLINE int ED_NeedsConst (const ExprDesc* Expr) +/* Check if the expression need be immutable */ +{ + return (Expr->Flags & E_EVAL_CONST) == E_EVAL_CONST; +} +#else +# define ED_NeedsConst(Expr) (((Expr)->Flags & E_EVAL_CONST) == E_EVAL_CONST) +#endif + +void ED_MarkForUneval (ExprDesc* Expr); +/* Mark the expression as not to be evaluated */ + +#if defined(HAVE_INLINE) +INLINE int ED_MayBeUneval (const ExprDesc* Expr) +/* Check if the expression may be uevaluated */ +{ + return (Expr->Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL; +} +#else +# define ED_MayBeUneval(Expr) (((Expr)->Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) +#endif + +#if defined(HAVE_INLINE) +INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr) +/* Check if the expression may be present without effects */ +{ + return (Expr->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED; +} +#else +# define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED) +#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 */ @@ -522,7 +617,7 @@ int ED_IsNullPtr (const ExprDesc* Expr); int ED_IsBool (const ExprDesc* Expr); /* Return true of the expression can be treated as a boolean, that is, it can -** be an operand to a compare operation. +** be an operand to a compare operation with 0/NULL. */ void PrintExprDesc (FILE* F, ExprDesc* Expr); diff --git a/src/cc65/goto.c b/src/cc65/goto.c index f1fb725d2..06364068f 100644 --- a/src/cc65/goto.c +++ b/src/cc65/goto.c @@ -80,6 +80,8 @@ void GotoStatement (void) CodeEntry *E; unsigned char val; + ED_Init (&desc); + NextToken (); /* arr[foo], we only support simple foo for now */ diff --git a/src/cc65/loadexpr.c b/src/cc65/loadexpr.c index f3a1a6add..5c5434393 100644 --- a/src/cc65/loadexpr.c +++ b/src/cc65/loadexpr.c @@ -145,7 +145,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) Flags |= TypeOf (Expr->Type); } - if (ED_NeedsTest (Expr)) { + if (ED_YetToTest (Expr)) { /* If we're only testing, we do not need to promote char to int. ** CF_FORCECHAR does nothing if the type is not CF_CHAR. */ @@ -234,7 +234,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) */ CHECK (Expr->BitOffs < CHAR_BITS); - if (ED_NeedsTest (Expr)) { + if (ED_YetToTest (Expr)) { g_testbitfield (Flags, Expr->BitOffs, Expr->BitWidth); } else { g_extractbitfield (Flags, BitFieldFullWidthFlags, IsSignSigned (Expr->Type), @@ -252,7 +252,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr) LoadAddress (Flags, Expr); /* Are we testing this value? */ - if (ED_NeedsTest (Expr)) { + if (ED_YetToTest (Expr)) { /* Yes, force a test */ g_test (Flags); ED_TestDone (Expr); diff --git a/src/cc65/locals.c b/src/cc65/locals.c index a21a09e8e..87c8e6cb9 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -122,8 +122,6 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg) /* Check for an optional initialization */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc Expr; - /* Skip the '=' */ NextToken (); @@ -152,6 +150,9 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg) } else { + ExprDesc Expr; + ED_Init (&Expr); + /* Parse the expression */ hie1 (&Expr); @@ -203,8 +204,6 @@ static void ParseAutoDecl (Declaration* Decl) /* Check for an optional initialization */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc Expr; - /* Skip the '=' */ NextToken (); @@ -242,6 +241,9 @@ static void ParseAutoDecl (Declaration* Decl) } else { + ExprDesc Expr; + ED_Init (&Expr); + /* Allocate previously reserved local space */ F_AllocLocalSpace (CurrentFunc); @@ -303,8 +305,6 @@ static void ParseAutoDecl (Declaration* Decl) /* Allow assignments */ if (CurTok.Tok == TOK_ASSIGN) { - ExprDesc Expr; - /* Skip the '=' */ NextToken (); @@ -328,6 +328,9 @@ static void ParseAutoDecl (Declaration* Decl) } else { + ExprDesc Expr; + ED_Init (&Expr); + /* Allocate space for the variable */ AllocStorage (DataLabel, g_usebss, Size); diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 1c4837d94..518570ff5 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1043,6 +1043,7 @@ static int DoIf (int Skip) /* Process #if directive */ { ExprDesc Expr; + ED_Init (&Expr); /* We're about to abuse the compiler expression parser to evaluate the ** #if expression. Save the current tokens to come back here later. diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index 9fe9d1188..0c69e96e5 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -61,7 +61,6 @@ void ShiftExpr (struct ExprDesc* Expr) /* Parse the << and >> operators. */ { - ExprDesc Expr2; CodeMark Mark1; CodeMark Mark2; token_t Tok; /* The operator token */ @@ -78,6 +77,10 @@ void ShiftExpr (struct ExprDesc* Expr) while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) { + ExprDesc Expr2; + ED_Init (&Expr2); + Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; + /* All operators that call this function expect an int on the lhs */ if (!IsClassInt (Expr->Type)) { Error ("Integer expression expected"); diff --git a/src/cc65/staticassert.c b/src/cc65/staticassert.c index 68f0a41bc..b963947b6 100644 --- a/src/cc65/staticassert.c +++ b/src/cc65/staticassert.c @@ -55,6 +55,8 @@ void ParseStaticAssert () ExprDesc Expr; int failed; + ED_Init (&Expr); + /* Skip the _Static_assert token itself */ CHECK (CurTok.Tok == TOK_STATIC_ASSERT); NextToken (); diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 94e56a625..8335177bb 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -152,6 +152,9 @@ static void ParseArg (ArgDesc* Arg, Type* Type) /* Remember the required argument type */ Arg->ArgType = Type; + /* Init expression */ + ED_Init (&Arg->Expr); + /* Read the expression we're going to pass to the function */ MarkedExprWithCheck (hie1, &Arg->Expr); @@ -1180,6 +1183,8 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) long ECount; unsigned L; + ED_Init (&Arg); + /* Setup the argument type string */ ArgType[1].C = T_CHAR | T_QUAL_CONST; diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 036cc2d89..ba9ae389f 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -312,6 +312,7 @@ static void ReturnStatement (void) ExprDesc Expr; const Type* ReturnType; + ED_Init (&Expr); NextToken (); if (CurTok.Tok != TOK_SEMI) { @@ -424,8 +425,6 @@ static void ContinueStatement (void) static void ForStatement (void) /* Handle a 'for' statement */ { - ExprDesc lval1; - ExprDesc lval3; int HaveIncExpr; CodeMark IncExprStart; CodeMark IncExprEnd; @@ -450,6 +449,10 @@ static void ForStatement (void) /* Parse the initializer expression */ if (CurTok.Tok != TOK_SEMI) { + /* The value of the expression is unused */ + ExprDesc lval1; + ED_Init (&lval1); + lval1.Flags = E_NEED_NONE; Expression0 (&lval1); } ConsumeSemi (); @@ -475,6 +478,10 @@ static void ForStatement (void) /* Parse the increment expression */ HaveIncExpr = (CurTok.Tok != TOK_RPAREN); if (HaveIncExpr) { + /* The value of the expression is unused */ + ExprDesc lval3; + ED_Init (&lval3); + lval3.Flags = E_NEED_NONE; Expression0 (&lval3); } @@ -580,8 +587,10 @@ int Statement (int* PendingToken) { ExprDesc Expr; int GotBreak; + unsigned PrevErrorCount; CodeMark Start, End; - unsigned PrevErrorCount = ErrorCount; + + ED_Init (&Expr); /* Assume no pending token */ if (PendingToken) { @@ -666,25 +675,24 @@ int Statement (int* PendingToken) break; default: - /* Remember the current code position */ + /* Remember the current error count and code position */ + PrevErrorCount = ErrorCount; GetCodePos (&Start); + /* Actual statement */ - ExprWithCheck (hie0, &Expr); - /* Load the result only if it is an lvalue and the type is - ** marked as volatile. Otherwise the load is useless. - */ - if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) { - LoadExpr (CF_NONE, &Expr); - } + Expr.Flags |= E_NEED_NONE; + Expression0 (&Expr); + /* If the statement didn't generate code, and is not of type ** void, emit a warning. */ GetCodePos (&End); - if (CodeRangeIsEmpty (&Start, &End) && - !IsTypeVoid (Expr.Type) && + if (!ED_YetToLoad (&Expr) && + !ED_MayHaveNoEffect (&Expr) && + CodeRangeIsEmpty (&Start, &End) && IS_Get (&WarnNoEffect) && PrevErrorCount == ErrorCount) { - Warning ("Statement has no effect"); + Warning ("Expression result unused"); } CheckSemi (PendingToken); } diff --git a/src/cc65/swstmt.c b/src/cc65/swstmt.c index 8cab93bba..524a31ddf 100644 --- a/src/cc65/swstmt.c +++ b/src/cc65/swstmt.c @@ -97,7 +97,6 @@ void SwitchStatement (void) SwitchCtrl* OldSwitch; /* Pointer to old switch control data */ SwitchCtrl SwitchData; /* New switch data */ - /* Eat the "switch" token */ NextToken (); @@ -105,6 +104,8 @@ void SwitchStatement (void) ** integer type. */ ConsumeLParen (); + + ED_Init (&SwitchExpr); Expression0 (&SwitchExpr); if (!IsClassInt (SwitchExpr.Type)) { Error ("Switch quantity is not an integer"); @@ -211,11 +212,11 @@ void CaseLabel (void) long Val; /* Case label value */ unsigned CodeLabel; /* Code label for this case */ - /* Skip the "case" token */ NextToken (); /* Read the selector expression */ + ED_Init (&CaseExpr); ConstAbsIntExpr (hie1, &CaseExpr); Val = CaseExpr.IVal; diff --git a/src/cc65/testexpr.c b/src/cc65/testexpr.c index 5bb7bf7e4..b924eaa40 100644 --- a/src/cc65/testexpr.c +++ b/src/cc65/testexpr.c @@ -58,6 +58,8 @@ unsigned Test (unsigned Label, int Invert) ExprDesc Expr; unsigned Result; + ED_Init (&Expr); + /* Read a boolean expression */ BoolExpr (hie0, &Expr); @@ -80,10 +82,8 @@ unsigned Test (unsigned Label, int Invert) /* Result is unknown */ Result = TESTEXPR_UNKNOWN; - /* If the expr hasn't set condition codes, set the force-test flag */ - if (!ED_IsTested (&Expr)) { - ED_MarkForTest (&Expr); - } + /* Set the test flag */ + ED_RequireTest (&Expr); /* Load the value into the primary register */ LoadExpr (CF_FORCECHAR, &Expr); diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index 0f67db107..930aef8d4 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -371,6 +371,11 @@ void TypeCast (ExprDesc* Expr) GetBasicTypeName (NewType)); } + /* If the new type is void, the cast expression can have no effects */ + if (IsTypeVoid (NewType)) { + Expr->Flags |= E_EVAL_MAYBE_UNUSED; + } + /* The result is always an rvalue */ ED_MarkExprAsRVal (Expr); }