* src/SDCCsymt.c (processFuncArgs): fixed superflous allocation noted
[fw/sdcc] / src / SDCCsymt.c
index 5f538398eb3ae764de52a8ec48911c0235195f55..4b4e00c415d2b9b4fe3e0205de41d813fb1c5985 100644 (file)
@@ -973,39 +973,82 @@ addSymChain (symbol * symHead)
 {
   symbol *sym = symHead;
   symbol *csym = NULL;
+  int error = 0;
 
   for (; sym != NULL; sym = sym->next)
     {
       changePointer(sym);
       checkTypeSanity(sym->etype, sym->name);
 
+      if (!sym->level && !(IS_SPEC(sym->etype) && IS_TYPEDEF(sym->etype)))
+        checkDecl (sym, 0);
+      
       /* if already exists in the symbol table then check if
          one of them is an extern definition if yes then
          then check if the type match, if the types match then
          delete the current entry and add the new entry      */
       if ((csym = findSymWithLevel (SymbolTab, sym)) &&
          csym->level == sym->level) {
-       
-       /* one definition extern ? */
-       if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype)) {
-         /* do types match ? */
-         if (compareType (csym->type, sym->type) != 1) {
-           /* no then error */
-           werror (E_EXTERN_MISMATCH, csym->name);
-           continue;
+
+       /* If the previous definition was for an array with incomplete */
+       /* type, and the new definition has completed the type, update */
+       /* the original type to match */
+       if (IS_DECL(csym->type) && DCL_TYPE(csym->type)==ARRAY
+           && IS_DECL(sym->type) && DCL_TYPE(sym->type)==ARRAY)
+         {
+           if (!DCL_ELEM(csym->type) && DCL_ELEM(sym->type))
+             DCL_ELEM(csym->type) = DCL_ELEM(sym->type);
          }
-       } else {
-         /* not extern */
-         if (compareType (csym->type, sym->type) != 1) {
-           werror (E_DUPLICATE, sym->name);
-           continue;
+
+       #if 0
+       /* If only one of the definitions used the "at" keyword, copy */
+       /* the address to the other. */
+       if (IS_SPEC(csym->etype) && SPEC_ABSA(csym->etype)
+           && IS_SPEC(sym->etype) && !SPEC_ABSA(sym->etype))
+         {
+           SPEC_ABSA (sym->etype) = 1;
+           SPEC_ADDR (sym->etype) = SPEC_ADDR (csym->etype);
+         }
+       if (IS_SPEC(csym->etype) && !SPEC_ABSA(csym->etype)
+           && IS_SPEC(sym->etype) && SPEC_ABSA(sym->etype))
+         {
+           SPEC_ABSA (csym->etype) = 1;
+           SPEC_ADDR (csym->etype) = SPEC_ADDR (sym->etype);
          }
+       #endif
+  
+        error = 0;        
+        if (csym->ival && sym->ival)
+          error = 1;
+       if (compareTypeExact (csym->type, sym->type, sym->level) != 1)
+          error = 1;
+        
+        if (error) {
+          /* one definition extern ? */
+         if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype))
+           werror (E_EXTERN_MISMATCH, sym->name);
+          else
+           werror (E_DUPLICATE, sym->name);
+         fprintf (stderr, "from type '");
+         printTypeChain (csym->type, stderr);
+         if (IS_SPEC (csym->etype) && SPEC_ABSA (csym->etype))
+           fprintf(stderr, " at 0x%x", SPEC_ADDR (csym->etype));
+         fprintf (stderr, "'\nto type '");
+         printTypeChain (sym->type, stderr);
+         if (IS_SPEC (sym->etype) && SPEC_ABSA (sym->etype))
+           fprintf(stderr, " at 0x%x", SPEC_ADDR (sym->etype));
+         fprintf (stderr, "'\n");
+         continue;
        }
+
+       if (csym->ival && !sym->ival)
+         sym->ival = csym->ival;
+
        /* delete current entry */
        deleteSym (SymbolTab, csym, csym->name);
        deleteFromSeg(csym);
       }
-
+      
       /* add new entry */
       addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
     }
@@ -1028,7 +1071,7 @@ funcInChain (sym_link * lnk)
 }
 
 /*------------------------------------------------------------------*/
-/* structElemType - returns the type info of a sturct member        */
+/* structElemType - returns the type info of a struct member        */
 /*------------------------------------------------------------------*/
 sym_link *
 structElemType (sym_link * stype, value * id)
@@ -1048,6 +1091,10 @@ structElemType (sym_link * stype, value * id)
            etype = getSpec (type);
            SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
                                 SPEC_SCLS (etype) : SPEC_SCLS (petype));
+            if (IS_SPEC (type))
+              SPEC_CONST (type) |= SPEC_CONST (stype);
+            else
+              DCL_PTR_CONST (type) |= SPEC_CONST (stype);
            return type;
          }
        fields = fields->next;
@@ -1291,7 +1338,7 @@ checkSClass (symbol * sym, int isProto)
       }
     }
   }
-  
+
   /* automatic symbols cannot be given   */
   /* an absolute address ignore it      */
   if (sym->level &&
@@ -1466,7 +1513,7 @@ cleanUpLevel (bucket ** table, int level)
 /* computeType - computes the resultant type from two types         */
 /*------------------------------------------------------------------*/
 sym_link *
-computeType (sym_link * type1, sym_link * type2)
+computeType (sym_link * type1, sym_link * type2, bool promoteCharToInt)
 {
   sym_link *rType;
   sym_link *reType;
@@ -1499,15 +1546,18 @@ computeType (sym_link * type1, sym_link * type2)
     rType = copyLinkChain (type2);
 
   reType = getSpec (rType);
-#if 0
-  if (SPEC_NOUN (reType) == V_CHAR)
+
+  /* avoid conflicting types */
+  reType->select.s._signed = 0;
+
+  if (IS_CHAR (reType) && promoteCharToInt)
     SPEC_NOUN (reType) = V_INT;
-#endif
 
-  /* if either of them unsigned but not val then make this unsigned */
-  if (((/*!IS_LITERAL(type1) &&*/ SPEC_USIGN (etype1)) ||
-       (/*!IS_LITERAL(type2) &&*/ SPEC_USIGN (etype2))) &&
-      !IS_FLOAT (reType))
+  if (   (   (   SPEC_USIGN (etype1)
+             && (getSize (etype1) >= getSize (reType)))
+         || (   SPEC_USIGN (etype2)
+             && (getSize (etype2) >= getSize (reType))))
+      && !IS_FLOAT (reType))
     SPEC_USIGN (reType) = 1;
   else
     SPEC_USIGN (reType) = 0;
@@ -1616,6 +1666,185 @@ compareType (sym_link * dest, sym_link * src)
   return 1;
 }
 
+/*--------------------------------------------------------------------*/
+/* compareTypeExact - will do type check return 1 if match exactly    */
+/*--------------------------------------------------------------------*/
+int
+compareTypeExact (sym_link * dest, sym_link * src, int level)
+{
+  STORAGE_CLASS srcScls, destScls;
+  
+  if (!dest && !src)
+    return 1;
+
+  if (dest && !src)
+    return 0;
+
+  if (src && !dest)
+    return 0;
+
+  /* if dest is a declarator then */
+  if (IS_DECL (dest))
+    {
+      if (IS_DECL (src))
+       {
+         if (DCL_TYPE (src) == DCL_TYPE (dest)) {
+           if ((DCL_TYPE (src) == ARRAY) && (DCL_ELEM (src) != DCL_ELEM (dest)))
+             return 0;
+           if (DCL_PTR_CONST (src) != DCL_PTR_CONST (dest))
+             return 0;
+           if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
+             return 0;
+           if (IS_FUNC(src))
+              {
+               value *exargs, *acargs, *checkValue;
+
+                /* verify function return type */
+               if (!compareTypeExact (dest->next, src->next, -1))
+                 return 0;
+               if (FUNC_ISISR (dest) != FUNC_ISISR (src))
+                 return 0;
+               if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+                 return 0;
+               if (IFFUNC_ISNAKED (dest) != IFFUNC_ISNAKED (src))
+                 return 0;
+               #if 0
+                if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt>1)
+                 return 0;
+                #endif
+
+               /* compare expected args with actual args */
+               exargs = FUNC_ARGS(dest);
+               acargs = FUNC_ARGS(src);
+
+               /* for all the expected args do */
+               for (; exargs && acargs; exargs = exargs->next, acargs = acargs->next)
+                 {
+                   //checkTypeSanity(acargs->etype, acargs->name);
+
+                   if (IS_AGGREGATE (acargs->type))
+                     {
+                       checkValue = copyValue (acargs);
+                       aggregateToPointer (checkValue);
+                     }
+                   else
+                     checkValue = acargs;
+
+                    #if 0
+                   if (!compareTypeExact (exargs->type, checkValue->type, -1))
+                      return 0;
+                    #endif
+                 }
+
+                 /* if one them ended we have a problem */
+                 if ((exargs && !acargs && !IS_VOID (exargs->type)) ||
+                     (!exargs && acargs && !IS_VOID (acargs->type)))
+                   return 0;                  
+                  return 1;
+              }
+           return compareTypeExact (dest->next, src->next, level);
+         }
+          return 0;
+       }
+      return 0;
+    }
+
+  /* if one is a specifier and the other is not */
+  if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
+      (IS_SPEC (dest) && !IS_SPEC (src)))
+    return 0;
+
+  /* if one of them is a void then ok */
+  if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+    return 0;
+
+  /* if they are both bitfields then if the lengths
+     and starts don't match */
+  if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
+      (SPEC_BLEN (dest) != SPEC_BLEN (src) ||
+       SPEC_BSTR (dest) != SPEC_BSTR (src)))
+    return 0;
+
+  if (IS_INTEGRAL (dest))
+    {
+      /* signedness must match */
+      if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+       return 0;
+      /* size must match */
+      if (SPEC_LONG (dest) != SPEC_LONG (src))
+       return 0;
+      if (SPEC_SHORT (dest) != SPEC_SHORT (src))
+       return 0;
+    }
+  
+  if (IS_STRUCT (dest))
+    {
+      if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+       return 0;
+    }
+
+  if (SPEC_CONST (dest) != SPEC_CONST (src))
+    return 0;
+  if (SPEC_VOLATILE (dest) != SPEC_VOLATILE (src))
+    return 0;
+  if (SPEC_STAT (dest) != SPEC_STAT (src))
+    return 0;
+  if (SPEC_ABSA (dest) != SPEC_ABSA (src))
+    return 0;
+  if (SPEC_ABSA (dest) && SPEC_ADDR (dest) != SPEC_ADDR (src))
+    return 0;
+      
+  destScls = SPEC_SCLS (dest);
+  srcScls = SPEC_SCLS (src);
+  
+  /* Compensate for const to const code change in checkSClass() */
+  if (!level & port->mem.code_ro && SPEC_CONST (dest))
+    {
+      if (srcScls == S_CODE && destScls == S_FIXED)
+       destScls = S_CODE;
+      if (destScls == S_CODE && srcScls == S_FIXED)
+       srcScls = S_CODE;
+    }
+
+  /* compensate for allocGlobal() */  
+  if ((srcScls == S_FIXED || srcScls == S_AUTO)
+      && port->mem.default_globl_map == xdata
+      && !level)
+    srcScls = S_XDATA;
+  
+  if (level>0 && !SPEC_STAT (dest))
+    {
+      /* Compensate for hack-o-matic in checkSClass() */
+      if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+       {
+         if (destScls == S_FIXED)
+           destScls = (options.useXstack ? S_XSTACK : S_STACK);
+         if (srcScls == S_FIXED)
+           srcScls = (options.useXstack ? S_XSTACK : S_STACK);
+       }
+      else if (TARGET_IS_DS390 || TARGET_IS_DS400 || options.useXstack)
+       {
+         if (destScls == S_FIXED)
+           destScls = S_XDATA;
+         if (srcScls == S_FIXED)
+           srcScls = S_XDATA;
+       }
+    }
+
+  if (srcScls != destScls)
+    {
+      #if 0
+      printf ("level = %d\n", level);
+      printf ("SPEC_SCLS (src) = %d, SPEC_SCLS (dest) = %d\n",
+               SPEC_SCLS (src), SPEC_SCLS (dest));
+      printf ("srcScls = %d, destScls = %d\n",srcScls, destScls);
+      #endif
+      return 0;
+    }
+  
+  return 1;
+}
+
 /*------------------------------------------------------------------*/
 /* inCalleeSaveList - return 1 if found in callee save list          */
 /*------------------------------------------------------------------*/
@@ -1714,6 +1943,12 @@ checkFunction (symbol * sym, symbol *csym)
     fprintf (stderr, "checkFunction: %s ", sym->name);
   }
 
+  if (!IS_DECL(sym->type) || DCL_TYPE(sym->type)!=FUNCTION)
+    {
+      werror(E_SYNTAX_ERROR, sym->name);
+      return 0;
+    }
+    
   /* make sure the type is complete and sane */
   checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
 
@@ -1772,6 +2007,7 @@ checkFunction (symbol * sym, symbol *csym)
       werror(E_PARAM_NAME_OMITTED, sym->name, argCnt);
     }
   }
+  argCnt--;
 
   if (!csym && !(csym = findSym (SymbolTab, sym, sym->name)))
     return 1;                  /* not defined nothing more to check  */
@@ -1805,6 +2041,17 @@ checkFunction (symbol * sym, symbol *csym)
     {
       werror (E_PREV_DEF_CONFLICT, csym->name, "_naked");
     }
+  
+  /* Really, reentrant should match regardless of argCnt, but     */
+  /* this breaks some existing code (the fp lib functions). If    */
+  /* the first argument is always passed the same way, this       */
+  /* lax checking is ok (but may not be true for in future ports) */
+  if (IFFUNC_ISREENT (csym->type) != IFFUNC_ISREENT (sym->type)
+      && argCnt>1)
+    {
+      //printf("argCnt = %d\n",argCnt);
+      werror (E_PREV_DEF_CONFLICT, csym->name, "reentrant");
+    }
 
   /* compare expected args with actual args */
   exargs = FUNC_ARGS(csym->type);
@@ -1980,10 +2227,13 @@ processFuncArgs (symbol * func)
          val->sym->etype = getSpec (val->sym->type);
          val->sym->_isparm = 1;
          strncpyz (val->sym->rname, val->name, sizeof(val->sym->rname));
+         #if 0
+         /* ?? static functions shouldn't imply static parameters - EEP */
          if (IS_SPEC(func->etype)) {
            SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
              SPEC_STAT (func->etype);
          }
+         #endif
          addSymChain (val->sym);
 
        }
@@ -1995,10 +2245,14 @@ processFuncArgs (symbol * func)
          val->sym->_isparm = 1;
          SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) =
            (options.model != MODEL_SMALL ? xdata : data);
+         
+         #if 0
+         /* ?? static functions shouldn't imply static parameters - EEP */
          if (IS_SPEC(func->etype)) {
            SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
              SPEC_STAT (func->etype);
          }
+         #endif
        }
       if (!isinSet(operKeyReset, val->sym)) {
        addSet (&operKeyReset, val->sym);
@@ -2385,8 +2639,8 @@ printTypeChainRaw (sym_link * start, FILE * of)
 /*-----------------------------------------------------------------*/
 /* powof2 - returns power of two for the number if number is pow 2 */
 /*-----------------------------------------------------------------*/
-int 
-powof2 (unsigned long num)
+int
+powof2 (TYPE_UDWORD num)
 {
   int nshifts = 0;
   int n1s = 0;
@@ -2429,7 +2683,7 @@ sym_link *floatType;
 static char *
 _mangleFunctionName(char *in)
 {
-  if (port->getMangledFunctionName) 
+  if (port->getMangledFunctionName)
     {
       return port->getMangledFunctionName(in);
     }
@@ -2753,3 +3007,63 @@ sym_link *validateLink(sym_link  *l,
     exit(-1);
     return l; // never reached, makes compiler happy.
 }
+
+/*--------------------------------------------------------------------*/
+/* newEnumType - create an integer type compatible with enumerations  */
+/*--------------------------------------------------------------------*/
+sym_link *
+newEnumType (symbol *enumlist)
+{
+  int min, max, v;
+  symbol *sym;
+  sym_link *type;
+
+  if (!enumlist)
+    {
+      type = newLink (SPECIFIER);
+      SPEC_NOUN (type) = V_INT;
+      return type;
+    }
+      
+  /* Determine the range of the enumerated values */
+  sym = enumlist;
+  min = max = (int) floatFromVal (valFromType (sym->type));
+  for (sym = sym->next; sym; sym = sym->next)
+    {
+      v = (int) floatFromVal (valFromType (sym->type));
+      if (v<min)
+        min = v;
+      if (v>max)
+        max = v;
+    }
+
+  /* Determine the smallest integer type that is compatible with this range */
+  type = newLink (SPECIFIER);
+  if (min>=0 && max<=255)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-128 && max<=127)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+    }
+  else if (min>=0 && max<=65535)
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-32768 && max<=32767)
+    {
+      SPEC_NOUN (type) = V_INT;
+    }
+  else
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_LONG (type) = 1;
+      if (min>=0)
+        SPEC_USIGN (type) = 1;
+    }
+  
+  return type;    
+}