]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Fixed several type conversion issues
[cc65] / src / cc65 / expr.c
index e5e21e3ce796c9831b388aaf05413a54e6b864bc..02b5d78e26c5a9bc4435a7705a44a74b42fbd67d 100644 (file)
@@ -31,8 +31,8 @@
 #include "scanner.h"
 #include "stdfunc.h"
 #include "symtab.h"
-#include "typecast.h"
 #include "typecmp.h"
+#include "typeconv.h"
 #include "expr.h"
 
 
@@ -87,7 +87,7 @@ static GenDesc GenOASGN  = { TOK_OR_ASSIGN,   GEN_NOPUSH,     g_or  };
 
 
 
-static int hie0 (ExprDesc *lval);
+int hie0 (ExprDesc *lval);
 /* Parse comma operator. */
 
 static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
@@ -195,94 +195,6 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
 
 
 
-unsigned assignadjust (type* lhst, ExprDesc* rhs)
-/* Adjust the type of the right hand expression so that it can be assigned to
- * the type on the left hand side. This function is used for assignment and
- * for converting parameters in a function call. It returns the code generator
- * flags for the operation. The type string of the right hand side will be
- * set to the type of the left hand side.
- */
-{
-    /* Get the type of the right hand side. Treat function types as
-     * pointer-to-function
-     */
-    type* rhst = rhs->Type;
-    if (IsTypeFunc (rhst)) {
-       rhst = PointerTo (rhst);
-    }
-
-    /* After calling this function, rhs will have the type of the lhs */
-    rhs->Type = lhst;
-
-    /* First, do some type checking */
-    if (IsTypeVoid (lhst) || IsTypeVoid (rhst)) {
-       /* If one of the sides are of type void, output a more apropriate
-        * error message.
-        */
-               Error ("Illegal type");
-    } else if (IsClassInt (lhst)) {
-               if (IsClassPtr (rhst)) {
-           /* Pointer -> int conversion */
-           Warning ("Converting pointer to integer without a cast");
-               } else if (!IsClassInt (rhst)) {
-           Error ("Incompatible types");
-       } else {
-           /* Convert the rhs to the type of the lhs. */
-           unsigned flags = TypeOf (rhst);
-                   if (rhs->Flags == E_MCONST) {
-               flags |= CF_CONST;
-           }
-                   return g_typecast (TypeOf (lhst), flags);
-        }
-    } else if (IsClassPtr (lhst)) {
-       if (IsClassPtr (rhst)) {
-           /* Pointer to pointer assignment is valid, if:
-            *   - both point to the same types, or
-            *   - the rhs pointer is a void pointer, or
-            *   - the lhs pointer is a void pointer.
-            */
-           if (!IsTypeVoid (Indirect (lhst)) && !IsTypeVoid (Indirect (rhst))) {
-               /* Compare the types */
-               switch (TypeCmp (lhst, rhst)) {
-
-                   case TC_INCOMPATIBLE:
-                       Error ("Incompatible pointer types");
-                       break;
-
-                   case TC_QUAL_DIFF:
-                       Error ("Pointer types differ in type qualifiers");
-                       break;
-
-                   default:
-                       /* Ok */
-                       break;
-               }
-           }
-       } else if (IsClassInt (rhst)) {
-           /* Int to pointer assignment is valid only for constant zero */
-           if (rhs->Flags != E_MCONST || rhs->ConstVal != 0) {
-               Warning ("Converting integer to pointer without a cast");
-           }
-       } else if (IsTypeFuncPtr (lhst) && IsTypeFunc(rhst)) {
-           /* Assignment of function to function pointer is allowed, provided
-            * that both functions have the same parameter list.
-            */
-           if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) {
-               Error ("Incompatible types");
-           }
-       } else {
-           Error ("Incompatible types");
-       }
-    } else {
-       Error ("Incompatible types");
-    }
-
-    /* Return an int value in all cases where the operands are not both ints */
-    return CF_INT;
-}
-
-
-
 void DefineData (ExprDesc* Expr)
 /* Output a data definition for the given expression */
 {
@@ -365,7 +277,7 @@ static void LoadConstant (unsigned Flags, ExprDesc* Expr)
 
 
 
-static int kcalc (int tok, long val1, long val2)
+static int kcalc (token_t tok, long val1, long val2)
 /* Calculate an operation with left and right operand constant. */
 {
     switch (tok) {
@@ -501,48 +413,54 @@ void CheckBoolExpr (ExprDesc* lval)
 
 
 
-void exprhs (unsigned flags, int k, ExprDesc* lval)
+void exprhs (unsigned Flags, int k, ExprDesc* Expr)
 /* Put the result of an expression into the primary register */
 {
     int f;
 
-    f = lval->Flags;
+    f = Expr->Flags;
     if (k) {
                /* Dereferenced lvalue */
-               flags |= TypeOf (lval->Type);
-       if (lval->Test & E_FORCETEST) {
-           flags |= CF_TEST;
-           lval->Test &= ~E_FORCETEST;
+               Flags |= TypeOf (Expr->Type);
+       if (Expr->Test & E_FORCETEST) {
+           Flags |= CF_TEST;
+           Expr->Test &= ~E_FORCETEST;
        }
-               if (f & E_MGLOBAL) {    /* ref to globalvar */
-                   /* Generate code */
-           flags |= GlobalModeFlags (f);
-                   g_getstatic (flags, lval->Name, lval->ConstVal);
+               if (f & E_MGLOBAL) {
+           /* Reference to a global variable */
+           Flags |= GlobalModeFlags (f);
+                   g_getstatic (Flags, Expr->Name, Expr->ConstVal);
                } else if (f & E_MLOCAL) {
-           /* ref to localvar */
-                   g_getlocal (flags, lval->ConstVal);
+           /* Reference to a local variable */
+                   g_getlocal (Flags, Expr->ConstVal);
        } else if (f & E_MCONST) {
-           /* ref to absolute address */
-           g_getstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0);
+           /* Reference to an absolute address */
+           g_getstatic (Flags | CF_ABSOLUTE, Expr->ConstVal, 0);
        } else if (f == E_MEOFFS) {
-           g_getind (flags, lval->ConstVal);
+           /* Reference to address in primary with offset in Expr */
+           g_getind (Flags, Expr->ConstVal);
        } else if (f != E_MREG) {
-           g_getind (flags, 0);
+           /* Reference with address in primary */
+           g_getind (Flags, 0);
+       }
+    } else {
+       /* An rvalue */
+       if (f == E_MEOFFS) {
+           /* reference not storable */
+           Flags |= TypeOf (Expr->Type);
+           g_inc (Flags | CF_CONST, Expr->ConstVal);
+       } else if ((f & E_MEXPR) == 0) {
+           /* Constant of some sort, load it into the primary */
+           LoadConstant (Flags, Expr);
        }
-    } else if (f == E_MEOFFS) {
-       /* reference not storable */
-       flags |= TypeOf (lval->Type);
-               g_inc (flags | CF_CONST, lval->ConstVal);
-    } else if ((f & E_MEXPR) == 0) {
-       /* Constant of some sort, load it into the primary */
-       LoadConstant (flags, lval);
     }
+
     /* Are we testing this value? */
-    if (lval->Test & E_FORCETEST) {
+    if (Expr->Test & E_FORCETEST) {
         /* Yes, force a test */
-       flags |= TypeOf (lval->Type);
-               g_test (flags);
-               lval->Test &= ~E_FORCETEST;
+       Flags |= TypeOf (Expr->Type);
+               g_test (Flags);
+               Expr->Test &= ~E_FORCETEST;
     }
 }
 
@@ -554,7 +472,7 @@ static unsigned FunctionParamList (FuncDesc* Func)
  * each parameter separately, or creating the parameter frame once and then
  * storing into this frame.
  * The function returns the size of the parameters pushed.
- */      
+ */
 {
     ExprDesc lval;
 
@@ -583,8 +501,7 @@ static unsigned FunctionParamList (FuncDesc* Func)
        FrameSize   = Func->ParamSize;
        if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) {
            /* Last parameter is not pushed */
-           const SymEntry* LastParam = Func->SymTab->SymTail;
-           FrameSize -= CheckedSizeOf (LastParam->Type);
+           FrameSize -= CheckedSizeOf (Func->LastParam->Type);
            --FrameParams;
        }
 
@@ -656,8 +573,8 @@ static unsigned FunctionParamList (FuncDesc* Func)
         * convert the actual argument to the type needed.
         */
                if (!Ellipsis) {
-           /* Promote the argument if needed */
-                   assignadjust (Param->Type, &lval);
+           /* Convert the argument to the parameter type if needed */
+            TypeConversion (&lval, 0, Param->Type);
 
            /* If we have a prototype, chars may be pushed as chars */
            Flags |= CF_FORCECHAR;
@@ -678,9 +595,17 @@ static unsigned FunctionParamList (FuncDesc* Func)
        } else {
            unsigned ArgSize = sizeofarg (Flags);
            if (FrameSize > 0) {
-               /* We have the space already allocated, store in the frame */
-               CHECK (FrameSize >= ArgSize);
-               FrameSize -= ArgSize;
+               /* We have the space already allocated, store in the frame.
+                 * Because of invalid type conversions (that have produced an
+                 * error before), we can end up here with a non aligned stack
+                 * frame. Since no output will be generated anyway, handle
+                 * these cases gracefully instead of doing a CHECK.
+                 */
+                if (FrameSize >= ArgSize) {
+                    FrameSize -= ArgSize;
+                } else {
+                    FrameSize = 0;
+                }
                FrameOffs -= ArgSize;
                /* Store */
                g_putlocal (Flags | CF_NOKEEP, FrameOffs, lval.ConstVal);
@@ -1105,9 +1030,10 @@ static int arrayref (int k, ExprDesc* lval)
            RemoveCode (Mark1);
 
            /* Handle constant base array on stack. Be sure NOT to
-            * handle pointers the same way, this won't work.
+            * handle pointers the same way, and check for character literals
+             * (both won't work).
             */
-           if (IsTypeArray (tptr1) &&
+           if (IsTypeArray (tptr1) && lval->Flags != (E_MCONST | E_TLIT) &&
                ((lval->Flags & ~E_MCTYPE) == E_MCONST ||
                (lval->Flags & ~E_MCTYPE) == E_MLOCAL ||
                (lval->Flags & E_MGLOBAL) != 0 ||
@@ -2656,48 +2582,58 @@ static int hieOr (ExprDesc *lval)
 
 
 
-static int hieQuest (ExprDesc *lval)
-/* Parse "lvalue ? exp : exp" */
+static int hieQuest (ExprDesclval)
+/* Parse the ternary operator */
 {
-    int k;
-    int labf;
-    int labt;
-    ExprDesc lval2;            /* Expression 2 */
-    ExprDesc lval3;            /* Expression 3 */
-    type* type2;               /* Type of expression 2 */
-    type* type3;               /* Type of expression 3 */
-    type* rtype;               /* Type of result */
+    int         k1, k2, k3;
+    int         labf;
+    int         labt;
+    ExprDesc   Expr2;          /* Expression 2 */
+    ExprDesc   Expr3;          /* Expression 3 */
+    int         Expr2IsNULL;    /* Expression 2 is a NULL pointer */
+    int         Expr3IsNULL;    /* Expression 3 is a NULL pointer */
+    type*      ResultType;     /* Type of result */
 
 
-    k = Preprocessing? hieOrPP (lval) : hieOr (lval);
+    k1 = Preprocessing? hieOrPP (lval) : hieOr (lval);
     if (CurTok.Tok == TOK_QUEST) {
        NextToken ();
        if ((lval->Test & E_CC) == 0) {
            /* Condition codes not set, force a test */
            lval->Test |= E_FORCETEST;
        }
-       exprhs (CF_NONE, k, lval);
+       exprhs (CF_NONE, k1, lval);
        labf = GetLocalLabel ();
        g_falsejump (CF_NONE, labf);
 
-       /* Parse second expression */
-        k = expr (hie1, &lval2);
-       type2 = lval2.Type;
-        if (!IsTypeVoid (lval2.Type)) {
+       /* Parse second expression. Remember for later if it is a NULL pointer
+         * expression, then load it into the primary.
+         */
+        k2 = expr (hie1, &Expr2);
+        Expr2IsNULL = IsNullPtr (&Expr2);
+        if (!IsTypeVoid (Expr2.Type)) {
             /* Load it into the primary */
-            exprhs (CF_NONE, k, &lval2);
+            exprhs (CF_NONE, k2, &Expr2);
+           Expr2.Flags = E_MEXPR;
+           k2 = 0;
         }
        labt = GetLocalLabel ();
        ConsumeColon ();
        g_jump (labt);
 
-        /* Parse the third expression */
+        /* Jump here if the first expression was false */
        g_defcodelabel (labf);
-        k = expr (hie1, &lval3);
-       type3 = lval3.Type;
-        if (!IsTypeVoid (lval3.Type)) {
+
+       /* Parse second expression. Remember for later if it is a NULL pointer
+         * expression, then load it into the primary.
+         */
+        k3 = expr (hie1, &Expr3);
+        Expr3IsNULL = IsNullPtr (&Expr3);
+        if (!IsTypeVoid (Expr3.Type)) {
             /* Load it into the primary */
-            exprhs (CF_NONE, k, &lval3);
+            exprhs (CF_NONE, k3, &Expr3);
+           Expr3.Flags = E_MEXPR;
+           k3 = 0;
         }
 
        /* Check if any conversions are needed, if so, do them.
@@ -2713,62 +2649,62 @@ static int hieQuest (ExprDesc *lval)
          *     type void.
         *   - all other cases are flagged by an error.
         */
-       if (IsClassInt (type2) && IsClassInt (type3)) {
+       if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
 
            /* Get common type */
-           rtype = promoteint (type2, type3);
+           ResultType = promoteint (Expr2.Type, Expr3.Type);
 
            /* Convert the third expression to this type if needed */
-           g_typecast (TypeOf (rtype), TypeOf (type3));
+           TypeConversion (&Expr3, k3, ResultType);
 
            /* Setup a new label so that the expr3 code will jump around
             * the type cast code for expr2.
             */
                    labf = GetLocalLabel ();    /* Get new label */
-           g_jump (labf);              /* Jump around code */
+           g_jump (labf);              /* Jump around code */
 
            /* The jump for expr2 goes here */
            g_defcodelabel (labt);
 
            /* Create the typecast code for expr2 */
-           g_typecast (TypeOf (rtype), TypeOf (type2));
+           TypeConversion (&Expr2, k2, ResultType);
 
            /* Jump here around the typecase code. */
            g_defcodelabel (labf);
-           labt = 0;           /* Mark other label as invalid */
+           labt = 0;           /* Mark other label as invalid */
 
-       } else if (IsClassPtr (type2) && IsClassPtr (type3)) {
+       } else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
            /* Must point to same type */
-           if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) {
-               Error ("Incompatible pointer types");
+           if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) {
+               Error ("Incompatible pointer types");
            }
            /* Result has the common type */
-           rtype = lval2.Type;
-       } else if (IsClassPtr (type2) && IsNullPtr (&lval3)) {
+           ResultType = Expr2.Type;
+       } else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) {
            /* Result type is pointer, no cast needed */
-           rtype = lval2.Type;
-       } else if (IsNullPtr (&lval2) && IsClassPtr (type3)) {
+           ResultType = Expr2.Type;
+       } else if (Expr2IsNULL && IsClassPtr (Expr3.Type)) {
            /* Result type is pointer, no cast needed */
-           rtype = lval3.Type;
-        } else if (IsTypeVoid (type2) && IsTypeVoid (type3)) {
+           ResultType = Expr3.Type;
+        } else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
             /* Result type is void */
-            rtype = lval3.Type;
-       } else {
-           Error ("Incompatible types");
-           rtype = lval2.Type;         /* Doesn't matter here */
-       }
+            ResultType = Expr3.Type;
+       } else {
+           Error ("Incompatible types");
+           ResultType = Expr2.Type;            /* Doesn't matter here */
+       }
 
-       /* If we don't have the label defined until now, do it */
-       if (labt) {
-           g_defcodelabel (labt);
-       }
+       /* If we don't have the label defined until now, do it */
+       if (labt) {
+           g_defcodelabel (labt);
+       }
 
-       /* Setup the target expression */
+       /* Setup the target expression */
                lval->Flags = E_MEXPR;
-       lval->Type = rtype;
-       k = 0;
+       lval->Type  = ResultType;
+       k1 = 0;
     }
-    return k;
+    return k1;
 }
 
 
@@ -2860,7 +2796,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k)
     ExprDesc lval2;
     unsigned lflags;
     unsigned rflags;
-    int MustScale;
+    int      MustScale;
 
 
     /* We must have an lvalue */
@@ -2889,16 +2825,18 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k)
     rflags = 0;
 
     /* Evaluate the rhs */
-    if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
+    k = hie1 (&lval2);
+    if (k == 0 && lval2.Flags == E_MCONST) {
        /* The resulting value is a constant. */
                if (MustScale) {
            /* lhs is a pointer, scale rhs */
            lval2.ConstVal *= CheckedSizeOf (lval->Type+1);
        }
        rflags |= CF_CONST;
-       lflags |= CF_CONST;
+       lflags |= CF_CONST;
     } else {
-       /* rhs is not constant and already in the primary register */
+       /* Not constant, load into the primary */
+        exprhs (CF_NONE, k, &lval2);
                if (MustScale) {
            /* lhs is a pointer, scale rhs */
                    g_scale (TypeOf (lval2.Type), CheckedSizeOf (lval->Type+1));
@@ -2909,7 +2847,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k)
     lflags |= TypeOf (lval->Type) | CF_FORCECHAR;
     rflags |= TypeOf (lval2.Type);
 
-    /* Cast the rhs to the type of the lhs */
+    /* Convert the type of the lhs to that of the rhs */
     g_typecast (lflags, rflags);
 
     /* Output apropriate code */
@@ -3022,12 +2960,10 @@ int hie1 (ExprDesc* lval)
 
 
 
-static int hie0 (ExprDesc *lval)
+int hie0 (ExprDesc *lval)
 /* Parse comma operator. */
 {
-    int k;
-
-    k = hie1 (lval);
+    int k = hie1 (lval);
     while (CurTok.Tok == TOK_COMMA) {
        NextToken ();
        k = hie1 (lval);