* src/SDCCsymt.c: fixed bug #1159134: invalid duplicate declarations
[fw/sdcc] / src / SDCCsymt.c
index 3ea2843fcbb3b92dea7bf4033e65bd8f6a8b6e85..8d16e7f7f07fc29ca525a6d6ed7db00ca7772542 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "common.h"
 #include "newalloc.h"
+#include "dbuf_string.h"
 
 #include "SDCCsymt.h"
 
@@ -43,7 +44,7 @@ char *nounName(sym_link *sl) {
     {
     case V_INT: {
       if (SPEC_LONG(sl)) return "long";
-      if (sl->select.s._short) return "short";
+      if (SPEC_SHORT(sl)) return "short";
       return "int";
     }
     case V_FLOAT: return "float";
@@ -295,8 +296,8 @@ newSymbol (char *name, int scope)
   strncpyz (sym->name, name, sizeof(sym->name));        /* copy the name */
   sym->level = scope;           /* set the level    */
   sym->block = currBlockno;
-  sym->lineDef = mylineno;      /* set the line number */
-  sym->fileDef = currFname;
+  sym->lineDef = lineno;        /* set the line number */
+  sym->fileDef = filename;
   return sym;
 }
 
@@ -438,6 +439,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
 void 
 addDecl (symbol * sym, int type, sym_link * p)
 {
+  static sym_link *empty = NULL;
   sym_link *head;
   sym_link *tail;
   sym_link *t;
@@ -445,6 +447,9 @@ addDecl (symbol * sym, int type, sym_link * p)
   if (getenv("SDCC_DEBUG_FUNCTION_POINTERS"))
     fprintf (stderr, "SDCCsymt.c:addDecl(%s,%d,%p)\n", sym->name, type, p);
 
+  if (empty == NULL)
+    empty = newLink(SPECIFIER);
+
   /* if we are passed a link then set head & tail */
   if (p)
     {
@@ -464,28 +469,28 @@ addDecl (symbol * sym, int type, sym_link * p)
       sym->type = head;
       sym->etype = tail;
     }
+  else if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
+    {
+      sym->etype = mergeSpec (sym->etype, head, sym->name);
+    }
+  else if (IS_SPEC (sym->etype) && !IS_SPEC (head) && head == tail)
+    {
+      t = sym->type;
+      while (t->next != sym->etype)
+        t = t->next;
+      t->next = head;
+      tail->next = sym->etype;
+    }
+  else if (IS_FUNC (sym->type) && IS_SPEC (sym->type->next) &&
+           !memcmp(sym->type->next, empty, sizeof(sym_link)))
+    {
+      sym->type->next = head;
+      sym->etype = tail;
+    }
   else
     {
-      if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
-        {
-          sym->etype = mergeSpec (sym->etype, head, sym->name);
-        }
-      else
-        {
-          if (IS_SPEC (sym->etype) && !IS_SPEC (head) && head == tail)
-            {
-              t = sym->type;
-              while (t->next != sym->etype)
-                t = t->next;
-              t->next = head;
-              tail->next = sym->etype;
-            }
-          else
-            {
-              sym->etype->next = head;
-              sym->etype = tail;
-            }
-        }
+      sym->etype->next = head;
+      sym->etype = tail;
     }
 
   /* if the type is an unknown pointer and has
@@ -545,7 +550,7 @@ void checkTypeSanity(sym_link *etype, char *name) {
        SPEC_NOUN(etype)==V_FIXED16X16 ||
        SPEC_NOUN(etype)==V_DOUBLE || 
        SPEC_NOUN(etype)==V_VOID) &&
-      (etype->select.s._short || SPEC_LONG(etype))) {
+      (SPEC_SHORT(etype) || SPEC_LONG(etype))) {
     // long or short for char float double or void
     werror (E_LONG_OR_SHORT_INVALID, noun, name);
   }
@@ -553,15 +558,15 @@ void checkTypeSanity(sym_link *etype, char *name) {
        SPEC_NOUN(etype)==V_FIXED16X16 ||
        SPEC_NOUN(etype)==V_DOUBLE || 
        SPEC_NOUN(etype)==V_VOID) && 
-      (etype->select.s._signed || SPEC_USIGN(etype))) {
+      (etype->select.s.b_signed || SPEC_USIGN(etype))) {
     // signed or unsigned for float double or void
     werror (E_SIGNED_OR_UNSIGNED_INVALID, noun, name);
   }
 
   // special case for "short"
-  if (etype->select.s._short) {
+  if (SPEC_SHORT(etype)) {
     SPEC_NOUN(etype) = options.shortis8bits ? V_CHAR : V_INT;
-    etype->select.s._short = 0;
+    SPEC_SHORT(etype) = 0;
   }
 
   /* if no noun e.g. 
@@ -575,15 +580,15 @@ void checkTypeSanity(sym_link *etype, char *name) {
   /* a "plain" int bitfield is unsigned */
   if (SPEC_NOUN(etype)==V_BIT ||
       SPEC_NOUN(etype)==V_SBIT) {
-    if (!etype->select.s._signed)
+    if (!etype->select.s.b_signed)
       SPEC_USIGN(etype) = 1;
   }
 
-  if (etype->select.s._signed && SPEC_USIGN(etype)) {
+  if (etype->select.s.b_signed && SPEC_USIGN(etype)) {
     // signed AND unsigned 
     werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
   }
-  if (etype->select.s._short && SPEC_LONG(etype)) {
+  if (SPEC_SHORT(etype) && SPEC_LONG(etype)) {
     // short AND long
     werror (E_LONG_AND_SHORT_INVALID, noun, name);
   }
@@ -645,14 +650,15 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   // but there are more important thing right now
 
   SPEC_LONG (dest) |= SPEC_LONG (src);
-  dest->select.s._short|=src->select.s._short;
+  SPEC_SHORT(dest) |= SPEC_SHORT(src);
   SPEC_USIGN (dest) |= SPEC_USIGN (src);
-  dest->select.s._signed|=src->select.s._signed;
+  dest->select.s.b_signed|=src->select.s.b_signed;
   SPEC_STAT (dest) |= SPEC_STAT (src);
   SPEC_EXTR (dest) |= SPEC_EXTR (src);
   SPEC_CONST(dest) |= SPEC_CONST (src);
   SPEC_ABSA (dest) |= SPEC_ABSA (src);
   SPEC_VOLATILE (dest) |= SPEC_VOLATILE (src);
+  SPEC_RESTRICT (dest) |= SPEC_RESTRICT (src);
   SPEC_ADDR (dest) |= SPEC_ADDR (src);
   SPEC_OCLS (dest) = SPEC_OCLS (src);
   SPEC_BLEN (dest) |= SPEC_BLEN (src);
@@ -782,7 +788,21 @@ newIntLink ()
 }
 
 /*------------------------------------------------------------------*/
-/* getSize - returns size of a type chain in bits                   */
+/* newBoolLink() - creates an bool type                             */
+/*------------------------------------------------------------------*/
+sym_link *
+newBoolLink ()
+{
+  sym_link *p;
+
+  p = newLink (SPECIFIER);
+  SPEC_NOUN (p) = V_BIT;
+
+  return p;
+}
+
+/*------------------------------------------------------------------*/
+/* getSize - returns size of a type chain in bytes                  */
 /*------------------------------------------------------------------*/
 unsigned int 
 getSize (sym_link * p)
@@ -846,29 +866,41 @@ getSize (sym_link * p)
     }
 }
 
-/*---------------------------------------------------------------------*/
-/* getAllocSize - returns size of a type chain in bytes for allocation */
-/*---------------------------------------------------------------------*/
-unsigned int
-getAllocSize (sym_link *p)
+/*------------------------------------------------------------------*/
+/* checkStructFlexArray - check tree behind a struct                */
+/*------------------------------------------------------------------*/
+static bool
+checkStructFlexArray (symbol *sym, sym_link *p)
 {
-  if (IS_STRUCT (p) && SPEC_STRUCT (p)->type == STRUCT)
-    {
-      /* if this is a struct specifier then  */
-      /* calculate the size as it could end  */
-      /* with an array of unspecified length */
-      symbol *sflds = SPEC_STRUCT (p)->fields;
+  /* if nothing return FALSE */
+  if (!p)
+    return FALSE;
 
-      while (sflds && sflds->next)
-        sflds = sflds->next;
+  if (IS_SPEC (p))
+    {
+      /* (nested) struct with flexible array member? */
+      if (IS_STRUCT (p) && SPEC_STRUCT (p)->b_flexArrayMember)
+        {
+          werror (W_INVALID_FLEXARRAY);
+          return FALSE;
+        }
+      return FALSE;
+    }
 
-      if (sflds && !IS_BITFIELD (sflds->type))
-        return sflds->offset + getAllocSize (sflds->type);
-      else
-        return SPEC_STRUCT (p)->size;
+  /* this is a declarator */
+  if (IS_ARRAY (p))
+    {
+      /* flexible array member? */
+      if (!DCL_ELEM(p))
+        {
+          if (!options.std_c99)
+            werror (W_C89_NO_FLEXARRAY);
+          return TRUE;
+        }
+      /* walk tree */
+      return checkStructFlexArray (sym, p->next);
     }
-  else
-    return getSize (p);
+  return FALSE;
 }
 
 /*------------------------------------------------------------------*/
@@ -1040,83 +1072,91 @@ addSymChain (symbol ** symHead)
 
       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) {
+          csym->level == sym->level)
+        {
+          /* if not formal parameter and not in file scope
+             then show symbol redefined error
+             else check if symbols have conpatible types */
+          if (!sym->_isparm && sym->level > 0)
+            error = 1;
+          else
+            {
+              /* 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);
+                }
 
-        /* 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);
-          }
+              #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
 
-        #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);
-          werrorfl (csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
-          #if 0
-          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");
-          #endif
-          continue;
+              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);
+              werrorfl (csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
+              #if 0
+              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");
+              #endif
+              continue;
+            }
+
+          if (csym->ival && !sym->ival)
+            sym->ival = csym->ival;
+
+          /* delete current entry */
+          deleteSym (SymbolTab, csym, csym->name);
+          deleteFromSeg(csym);
+
+          symPtrPtr = symHead;
+          while (*symPtrPtr && *symPtrPtr != csym)
+            symPtrPtr = &(*symPtrPtr)->next;
+          if (*symPtrPtr == csym)
+            *symPtrPtr = csym->next;
         }
 
-        if (csym->ival && !sym->ival)
-          sym->ival = csym->ival;
-
-        /* delete current entry */
-        deleteSym (SymbolTab, csym, csym->name);
-        deleteFromSeg(csym);
-        
-        symPtrPtr = symHead;
-        while (*symPtrPtr && *symPtrPtr != csym)
-          symPtrPtr = &(*symPtrPtr)->next;
-        if (*symPtrPtr == csym)
-          *symPtrPtr = csym->next;
-          
-      }
-      
       /* add new entry */
       addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
     }
@@ -1149,7 +1189,7 @@ structElemType (sym_link * stype, value * id)
   sym_link *petype = getSpec (stype);
 
   if (fields && id) {
-    
+
     /* look for the id */
     while (fields)
       {
@@ -1170,7 +1210,7 @@ structElemType (sym_link * stype, value * id)
   }
 
   werror (E_NOT_MEMBER, id->name);
-    
+
   // the show must go on
   return newIntLink();
 }
@@ -1198,100 +1238,131 @@ getStructElement (structdef * sdef, symbol * sym)
 int 
 compStructSize (int su, structdef * sdef)
 {
-    int sum = 0, usum = 0;
-    int bitOffset = 0;
-    symbol *loop;
-
-    /* for the identifiers  */
-    loop = sdef->fields;
-    while (loop) {
-
-        /* create the internal name for this variable */
-        SNPRINTF (loop->rname, sizeof(loop->rname), "_%s", loop->name);
-        if (su == UNION) {
-            sum = 0;
-            bitOffset = 0;
+  int sum = 0, usum = 0;
+  int bitOffset = 0;
+  symbol *loop;
+
+  /* for the identifiers  */
+  loop = sdef->fields;
+  while (loop) {
+
+    /* create the internal name for this variable */
+    SNPRINTF (loop->rname, sizeof(loop->rname), "_%s", loop->name);
+    if (su == UNION) {
+        sum = 0;
+        bitOffset = 0;
+    }
+    SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
+
+    /* if this is a bit field  */
+    if (loop->bitVar) {
+
+      /* change it to a unsigned bit */
+      SPEC_NOUN (loop->etype) = V_BITFIELD;
+      /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+      /* a "plain" int bitfield is unsigned */
+      if (!loop->etype->select.s.b_signed)
+        SPEC_USIGN(loop->etype) = 1;
+
+      SPEC_BLEN (loop->etype) = loop->bitVar;
+
+      if (loop->bitVar == BITVAR_PAD) {
+        /* A zero length bitfield forces padding */
+        SPEC_BSTR (loop->etype) = bitOffset;
+        SPEC_BLEN (loop->etype) = 0;
+        bitOffset = 8;
+        loop->offset = sum;
+      }
+      else {
+        if (bitOffset == 8) {
+          bitOffset = 0;
+          sum++;
         }
-        SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
-
-        /* if this is a bit field  */
-        if (loop->bitVar) {
-
-            /* change it to a unsigned bit */
-            SPEC_NOUN (loop->etype) = V_BITFIELD;
-            SPEC_USIGN (loop->etype) = 1;
-            SPEC_BLEN (loop->etype) = loop->bitVar;
-
-            if (loop->bitVar == BITVAR_PAD) {
-                /* A zero length bitfield forces padding */
-                SPEC_BSTR (loop->etype) = bitOffset;
-                SPEC_BLEN (loop->etype) = 0;
-                bitOffset = 8;
-                loop->offset = sum;
-            }
-            else {
-                if (bitOffset == 8) {
-                    bitOffset = 0;
-                    sum++;
-                }
-                /* check if this fit into the remaining   */
-                /* bits of this byte else align it to the */
-                /* next byte boundary                     */
-                if (loop->bitVar <= (8 - bitOffset)) {
-                    /* fits into current byte */
-                    loop->offset = sum;
-                    SPEC_BSTR (loop->etype) = bitOffset;
-                    bitOffset += loop->bitVar;
-                }
-                else if (!bitOffset) {
-                    /* does not fit, but is already byte aligned */
-                    loop->offset = sum;
-                    SPEC_BSTR (loop->etype) = bitOffset;
-                    bitOffset += loop->bitVar;
-                } 
-                else {
-                    /* does not fit; need to realign first */
-                    sum++;
-                    loop->offset = (su == UNION ? sum = 0 : sum);
-                    bitOffset = 0;
-                    SPEC_BSTR (loop->etype) = bitOffset;
-                    bitOffset += loop->bitVar;
-                }
-                while (bitOffset>8) {
-                    bitOffset -= 8;
-                    sum++;
-                } 
-            }
+        /* check if this fit into the remaining   */
+        /* bits of this byte else align it to the */
+        /* next byte boundary                     */
+        if (loop->bitVar <= (8 - bitOffset)) {
+          /* fits into current byte */
+          loop->offset = sum;
+          SPEC_BSTR (loop->etype) = bitOffset;
+          bitOffset += loop->bitVar;
         }
+        else if (!bitOffset) {
+          /* does not fit, but is already byte aligned */
+          loop->offset = sum;
+          SPEC_BSTR (loop->etype) = bitOffset;
+          bitOffset += loop->bitVar;
+        } 
         else {
-            /* This is a non-bit field. Make sure we are */
-            /* byte aligned first */
-            if (bitOffset) {
-                sum++;
-                loop->offset = (su == UNION ? sum = 0 : sum);
-                bitOffset = 0;
-            }
-            loop->offset = sum;
-            checkDecl (loop, 1);
-            sum += getSize (loop->type);
+          if( TARGET_IS_PIC16 && getenv("PIC16_PACKED_BITFIELDS") ) {
+            /* if PIC16 && enviroment variable is set, then
+             * tightly pack bitfields, this means that when a
+             * bitfield goes beyond byte alignment, do not
+             * automatically start allocatint from next byte,
+             * but also use the available bits first */
+            fprintf(stderr, ": packing bitfields in structures\n");
+            SPEC_BSTR (loop->etype) = bitOffset;
+            bitOffset += loop->bitVar;
+            loop->offset = (su == UNION ? sum = 0 : sum);
+          } else {
+            /* does not fit; need to realign first */
+            sum++;
+            loop->offset = (su == UNION ? sum = 0 : sum);
+            bitOffset = 0;
+            SPEC_BSTR (loop->etype) = bitOffset;
+            bitOffset += loop->bitVar;
+          }
         }
-
-        loop = loop->next;
-
-        /* if union then size = sizeof largest field */
-        if (su == UNION) {
-            /* For UNION, round up after each field */
-            sum += ((bitOffset+7)/8);
-            usum = max (usum, sum);
+        while (bitOffset>8) {
+          bitOffset -= 8;
+          sum++;
+        }
+      }
+    }
+    else {
+      /* This is a non-bit field. Make sure we are */
+      /* byte aligned first */
+      if (bitOffset) {
+        sum++;
+        loop->offset = (su == UNION ? sum = 0 : sum);
+        bitOffset = 0;
+      }
+      loop->offset = sum;
+      checkDecl (loop, 1);
+      sum += getSize (loop->type);
+
+      /* search for "flexibel array members" */
+      /* and do some syntax checks */
+      if (   su == STRUCT
+          && checkStructFlexArray (loop, loop->type))
+        {
+          /* found a "flexible array member" */
+          sdef->b_flexArrayMember = TRUE;
+          /* is another struct-member following? */
+          if (loop->next)
+            werror (E_FLEXARRAY_NOTATEND);
+          /* is it the first struct-member? */
+          else if (loop == sdef->fields)
+            werror (E_FLEXARRAY_INEMPTYSTRCT);
         }
+    }
+
+    loop = loop->next;
 
+    /* if union then size = sizeof largest field */
+    if (su == UNION) {
+      /* For UNION, round up after each field */
+      sum += ((bitOffset+7)/8);
+      usum = max (usum, sum);
     }
-    
-    /* For STRUCT, round up after all fields processed */
-    if (su != UNION)
-        sum += ((bitOffset+7)/8);
 
-    return (su == UNION ? usum : sum);
+  }
+
+  /* For STRUCT, round up after all fields processed */
+  if (su != UNION)
+    sum += ((bitOffset+7)/8);
+
+  return (su == UNION ? usum : sum);
 }
 
 /*-------------------------------------------------------------------*/
@@ -1371,8 +1442,7 @@ checkSClass (symbol * sym, int isProto)
     fprintf (stderr, "checkSClass: %s \n", sym->name);
   }
   
-  /* type is literal can happen for enums change
-     to auto */
+  /* type is literal can happen for enums change to auto */
   if (SPEC_SCLS (sym->etype) == S_LITERAL && !SPEC_ENUM (sym->etype))
     SPEC_SCLS (sym->etype) = S_AUTO;
   
@@ -1383,6 +1453,24 @@ checkSClass (symbol * sym, int isProto)
       SPEC_VOLATILE (sym->etype) = 1;
     }
   
+  /* make sure restrict is only used with pointers */
+  if (SPEC_RESTRICT (sym->etype))
+    {
+      werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+      SPEC_RESTRICT (sym->etype) = 0;
+    }
+  t = sym->type;
+  while (t)
+    {
+      if (IS_DECL (t) && DCL_PTR_RESTRICT (t) && !IS_PTR (t))
+        {
+          werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+          DCL_PTR_RESTRICT (t) = 0;
+          break;
+        }
+      t = t->next;
+    }
+  
   /* if absolute address given then it mark it as
      volatile -- except in the PIC port */
 
@@ -1478,16 +1566,18 @@ checkSClass (symbol * sym, int isProto)
 
   /* if this is an automatic symbol */
   if (sym->level && (options.stackAuto || reentrant)) {
-    if ((SPEC_SCLS (sym->etype) == S_AUTO ||
-         SPEC_SCLS (sym->etype) == S_FIXED ||
-         SPEC_SCLS (sym->etype) == S_REGISTER ||
-         SPEC_SCLS (sym->etype) == S_STACK ||
-         SPEC_SCLS (sym->etype) == S_XSTACK)) {
-      SPEC_SCLS (sym->etype) = S_AUTO;
-    } else {
-      /* storage class may only be specified for statics */
-      if (!IS_STATIC(sym->etype)) {
-        werror (E_AUTO_ASSUMED, sym->name);
+    if (SPEC_SCLS (sym->etype) != S_BIT) {
+      if ((SPEC_SCLS (sym->etype) == S_AUTO ||
+           SPEC_SCLS (sym->etype) == S_FIXED ||
+           SPEC_SCLS (sym->etype) == S_REGISTER ||
+           SPEC_SCLS (sym->etype) == S_STACK ||
+           SPEC_SCLS (sym->etype) == S_XSTACK)) {
+        SPEC_SCLS (sym->etype) = S_AUTO;
+      } else {
+        /* storage class may only be specified for statics */
+        if (!IS_STATIC(sym->etype)) {
+          werror (E_AUTO_ASSUMED, sym->name);
+        }
       }
     }
   }
@@ -1505,6 +1595,7 @@ checkSClass (symbol * sym, int isProto)
   /* arrays & pointers cannot be defined for bits   */
   /* SBITS or SFRs or BIT                           */
   if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
+      !IS_FUNCPTR (sym->type) &&
       (SPEC_NOUN (sym->etype) == V_BIT ||
        SPEC_NOUN (sym->etype) == V_SBIT ||
        SPEC_NOUN (sym->etype) == V_BITFIELD ||
@@ -1528,6 +1619,7 @@ checkSClass (symbol * sym, int isProto)
         //!sym->level &&
         port->mem.code_ro &&
         !IS_EXTERN (sym->etype) &&
+        !SPEC_ABSA (sym->etype) &&
         !funcInChain (sym->type))
       werror (E_CODE_NO_INIT, sym->name);
   }
@@ -1604,6 +1696,7 @@ copyLinkChain (sym_link * p)
 {
   sym_link *head, *curr, *loop;
 
+  /* note: v_struct and v_struct->fields are not copied! */
   curr = p;
   head = loop = (curr ? newLink (p->class) : (void *) NULL);
   while (curr)
@@ -1751,24 +1844,20 @@ computeType (sym_link * type1, sym_link * type2,
   /* which ever is greater in size */
   if (IS_FLOAT (etype1) || IS_FLOAT (etype2))
     rType = newFloatLink ();
-  else
-    /* if both are fixed16x16 then result is float */
-  if (IS_FIXED16X16(etype1) && IS_FIXED16X16(etype2))
+  /* if both are fixed16x16 then result is float */
+  else if (IS_FIXED16X16(etype1) && IS_FIXED16X16(etype2))
     rType = newFixed16x16Link();
-  else
-  if (IS_FIXED16X16(etype1) && IS_FLOAT (etype2))
+  else if (IS_FIXED16X16(etype1) && IS_FLOAT (etype2))
     rType = newFloatLink ();
-  if (IS_FLOAT (etype1) && IS_FIXED16X16 (etype2) )
+  else if (IS_FLOAT (etype1) && IS_FIXED16X16 (etype2) )
     rType = newFloatLink ();
-  else
-    /* if both are bitvars choose the larger one */
-  if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
-    {
-      rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ?
-                copyLinkChain (type1) : copyLinkChain (type1);
-    }
-    /* if only one of them is a bit variable
-       then the other one prevails */
+            
+  /* if both are bitvars choose the larger one */
+  else if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
+    rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ?
+            copyLinkChain (type1) : copyLinkChain (type1);
+                          
+  /* if only one of them is a bit variable then the other one prevails */
   else if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
     {
       rType = copyLinkChain (type2);
@@ -1783,10 +1872,9 @@ computeType (sym_link * type1, sym_link * type2,
       if (getSize (etype2) > 1)
         SPEC_NOUN (getSpec (rType)) = V_INT;
     }
-  else
-    /* if one of them is a pointer or array then that
-       prevails */
-  if (IS_PTR (type1) || IS_ARRAY (type1))
+  /* if one of them is a pointer or array then that
+     prevails */
+  else if (IS_PTR (type1) || IS_ARRAY (type1))
     rType = copyLinkChain (type1);
   else if (IS_PTR (type2) || IS_ARRAY (type2))
     rType = copyLinkChain (type2);
@@ -1798,7 +1886,7 @@ computeType (sym_link * type1, sym_link * type2,
   reType = getSpec (rType);
 
   /* avoid conflicting types */
-  reType->select.s._signed = 0;
+  reType->select.s.b_signed = 0;
 
   /* if result is a literal then make not so */
   if (IS_LITERAL (reType))
@@ -1836,28 +1924,34 @@ computeType (sym_link * type1, sym_link * type2,
           }
         else if (IS_CHAR (reType))
           {
-            if (op == '|' || op == '^')
-              return computeTypeOr (etype1, etype2, reType);
-            else if (   op == '&'
-                     && SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
-              {
-                SPEC_USIGN (reType) = 1;
-                return rType;
-              }
-            else if (op == '*')
-              {
-                SPEC_NOUN (reType) = V_INT;
-                SPEC_USIGN (reType) = 0;
-                return rType;
-              }
-            /* TODO: should be in SDCCast.c */
-            else if (   op == '/'
-                     && (   !SPEC_USIGN (etype1)
-                         || !SPEC_USIGN (etype2)))
+            /* promotion of some special cases */
+            switch (op)
               {
-                SPEC_NOUN (reType) = V_INT;
-                SPEC_USIGN (reType) = 0;
-                return rType;
+                case '|':
+                case '^':
+                  return computeTypeOr (etype1, etype2, reType);
+                case '&':
+                  if (SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+                    {
+                      SPEC_USIGN (reType) = 1;
+                      return rType;
+                    }
+                  break;
+                case '*':
+                  SPEC_NOUN (reType) = V_INT;
+                  SPEC_USIGN (reType) = 0;
+                  return rType;
+                case '/':
+                  /* if both are unsigned char then no promotion required */
+                  if (!(SPEC_USIGN (etype1) && SPEC_USIGN (etype2)))
+                    {
+                      SPEC_NOUN (reType) = V_INT;
+                      SPEC_USIGN (reType) = 0;
+                      return rType;
+                    }
+                  break;
+                default:
+                  break;
               }
           }
         break;
@@ -1904,12 +1998,12 @@ computeType (sym_link * type1, sym_link * type2,
       && (   (SPEC_USIGN (etype1)
               /* if this operand is promoted to a larger type,
                  then it will be promoted to a signed type */
-              && !(getSize (etype1) < getSize (reType))
+              && !(bitsForType (etype1) < bitsForType (reType))
               /* char require special handling */
               && !IS_CHAR (etype1))
           || /* same for 2nd operand */  
              (SPEC_USIGN (etype2)
-              && !(getSize (etype2) < getSize (reType))
+              && !(bitsForType (etype2) < bitsForType (reType))
               && !IS_CHAR (etype2))
           || /* if both are 'unsigned char' and not promoted
                 let the result be unsigned too */
@@ -2341,13 +2435,6 @@ checkFunction (symbol * sym, symbol *csym)
       return 0;
     }
 
-  /* function cannot return bit */
-  if (IS_BITVAR (sym->type->next))
-    {
-      werror (E_FUNC_BIT, sym->name);
-      return 0;
-    }
-
   /* check if this function is defined as calleeSaves
      then mark it as such */
   FUNC_CALLEESAVES(sym->type) = inCalleeSaveList (sym->name);
@@ -2525,6 +2612,22 @@ void cdbStructBlock (int block)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* processFuncPtrArgs - does some processing with args of func ptrs*/
+/*-----------------------------------------------------------------*/
+void 
+processFuncPtrArgs (sym_link * funcType)
+{
+  value *val = FUNC_ARGS(funcType);
+
+  /* if it is void then remove parameters */
+  if (val && IS_VOID (val->type))
+    {
+      FUNC_ARGS(funcType) = NULL;
+      return;
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* processFuncArgs - does some processing with function args       */
 /*-----------------------------------------------------------------*/
@@ -2578,7 +2681,7 @@ processFuncArgs (symbol * func)
          the function does not have VA_ARG
          and as port dictates */
       if (!IFFUNC_HASVARARGS(funcType) &&
-          (argreg = (*port->reg_parm) (val->type)))
+          (argreg = (*port->reg_parm) (val->type, FUNC_ISREENT(funcType))))
         {
           SPEC_REGPARM (val->etype) = 1;
           SPEC_ARGREG(val->etype) = argreg;
@@ -2649,7 +2752,7 @@ processFuncArgs (symbol * func)
             SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) = bit;
           else
             SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) =
-              (options.model != MODEL_SMALL ? xdata : data);
+              port->mem.default_local_map;
           
           #if 0
           /* ?? static functions shouldn't imply static parameters - EEP */
@@ -2659,6 +2762,8 @@ processFuncArgs (symbol * func)
           }
           #endif
         }
+      if (SPEC_OCLS (val->sym->etype) == pdata)
+        val->sym->iaccess = 1;
       if (!isinSet(operKeyReset, val->sym)) {
         addSet (&operKeyReset, val->sym);
         applyToSet (operKeyReset, resetParmKey);
@@ -2699,10 +2804,8 @@ void PT(sym_link *type)
 void
 printTypeChain (sym_link * start, FILE * of)
 {
+  struct dbuf_s dbuf;
   int nlr = 0;
-  value *args;
-  sym_link * type, * search;
-  STORAGE_CLASS scls;
 
   if (!of)
     {
@@ -2710,8 +2813,23 @@ printTypeChain (sym_link * start, FILE * of)
       nlr = 1;
     }
 
+  dbuf_init (&dbuf, 1024);
+  dbuf_printTypeChain (start, &dbuf);
+  dbuf_write_and_destroy (&dbuf, of);
+
+  if (nlr)
+    putc ('\n', of);
+}
+
+void
+dbuf_printTypeChain (sym_link * start, struct dbuf_s *dbuf)
+{
+  value *args;
+  sym_link * type, * search;
+  STORAGE_CLASS scls;
+
   if (start==NULL) {
-    fprintf (of, "void");
+    dbuf_append_str (dbuf, "void");
     return;
   }
 
@@ -2731,18 +2849,18 @@ printTypeChain (sym_link * start, FILE * of)
       if (type==start) {
         switch (scls) 
           {
-          case S_DATA: fprintf (of, "data-"); break;
-          case S_XDATA: fprintf (of, "xdata-"); break;
-          case S_SFR: fprintf (of, "sfr-"); break;
-          case S_SBIT: fprintf (of, "sbit-"); break;
-          case S_CODE: fprintf (of, "code-"); break;
-          case S_IDATA: fprintf (of, "idata-"); break;
-          case S_PDATA: fprintf (of, "pdata-"); break;
-          case S_LITERAL: fprintf (of, "literal-"); break;
-          case S_STACK: fprintf (of, "stack-"); break;
-          case S_XSTACK: fprintf (of, "xstack-"); break;
-          case S_BIT: fprintf (of, "bit-"); break;
-          case S_EEPROM: fprintf (of, "eeprom-"); break;
+          case S_DATA: dbuf_append_str (dbuf, "data-"); break;
+          case S_XDATA: dbuf_append_str (dbuf, "xdata-"); break;
+          case S_SFR: dbuf_append_str (dbuf, "sfr-"); break;
+          case S_SBIT: dbuf_append_str (dbuf, "sbit-"); break;
+          case S_CODE: dbuf_append_str (dbuf, "code-"); break;
+          case S_IDATA: dbuf_append_str (dbuf, "idata-"); break;
+          case S_PDATA: dbuf_append_str (dbuf, "pdata-"); break;
+          case S_LITERAL: dbuf_append_str (dbuf, "literal-"); break;
+          case S_STACK: dbuf_append_str (dbuf, "stack-"); break;
+          case S_XSTACK: dbuf_append_str (dbuf, "xstack-"); break;
+          case S_BIT: dbuf_append_str (dbuf, "bit-"); break;
+          case S_EEPROM: dbuf_append_str (dbuf, "eeprom-"); break;
           default: break;
           }
       }
@@ -2751,57 +2869,57 @@ printTypeChain (sym_link * start, FILE * of)
         {
           if (!IS_FUNC(type)) {
             if (DCL_PTR_VOLATILE (type)) {
-              fprintf (of, "volatile-");
+              dbuf_append_str (dbuf, "volatile-");
             }
             if (DCL_PTR_CONST (type)) {
-              fprintf (of, "const-");
+              dbuf_append_str (dbuf, "const-");
             }
           }
           switch (DCL_TYPE (type))
             {
             case FUNCTION:
-              fprintf (of, "function %s %s", 
+              dbuf_printf (dbuf, "function %s %s", 
                        (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
                        (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
-              fprintf (of, "( ");
+              dbuf_append_str (dbuf, "( ");
               for (args = FUNC_ARGS(type); 
                    args; 
                    args=args->next) {
-                printTypeChain(args->type, of);
+                dbuf_printTypeChain(args->type, dbuf);
                 if (args->next)
-                  fprintf(of, ", ");
+                  dbuf_append_str (dbuf, ", ");
               }
-              fprintf (of, ") ");
+              dbuf_append_str (dbuf, ") ");
               break;
             case GPOINTER:
-              fprintf (of, "generic* ");
+              dbuf_append_str (dbuf, "generic* ");
               break;
             case CPOINTER:
-              fprintf (of, "code* ");
+              dbuf_append_str (dbuf, "code* ");
               break;
             case FPOINTER:
-              fprintf (of, "xdata* ");
+              dbuf_append_str (dbuf, "xdata* ");
               break;
             case EEPPOINTER:
-              fprintf (of, "eeprom* ");
+              dbuf_append_str (dbuf, "eeprom* ");
               break;
             case POINTER:
-              fprintf (of, "near* ");
+              dbuf_append_str (dbuf, "near* ");
               break;
             case IPOINTER:
-              fprintf (of, "idata* ");
+              dbuf_append_str (dbuf, "idata* ");
               break;
             case PPOINTER:
-              fprintf (of, "pdata* ");
+              dbuf_append_str (dbuf, "pdata* ");
               break;
             case UPOINTER:
-              fprintf (of, "unknown* ");
+              dbuf_append_str (dbuf, "unknown* ");
               break;
             case ARRAY:
               if (DCL_ELEM(type)) {
-                fprintf (of, "[%d] ", DCL_ELEM(type));
+                dbuf_printf (dbuf, "[%d] ", DCL_ELEM(type));
               } else {
-                fprintf (of, "[] ");
+                dbuf_append_str (dbuf, "[] ");
               }
               break;
             }
@@ -2809,57 +2927,57 @@ printTypeChain (sym_link * start, FILE * of)
       else
         {
           if (SPEC_VOLATILE (type))
-            fprintf (of, "volatile-");
+            dbuf_append_str (dbuf, "volatile-");
           if (SPEC_CONST (type))
-            fprintf (of, "const-");
+            dbuf_append_str (dbuf, "const-");
           if (SPEC_USIGN (type))
-            fprintf (of, "unsigned-");
+            dbuf_append_str (dbuf, "unsigned-");
           switch (SPEC_NOUN (type))
             {
             case V_INT:
               if (IS_LONG (type))
-                fprintf (of, "long-");
-              fprintf (of, "int");
+                dbuf_append_str (dbuf, "long-");
+              dbuf_append_str (dbuf, "int");
               break;
 
             case V_CHAR:
-              fprintf (of, "char");
+              dbuf_append_str (dbuf, "char");
               break;
 
             case V_VOID:
-              fprintf (of, "void");
+              dbuf_append_str (dbuf, "void");
               break;
 
             case V_FLOAT:
-              fprintf (of, "float");
+              dbuf_append_str (dbuf, "float");
               break;
 
             case V_FIXED16X16:
-              fprintf (of, "fixed16x16");
+              dbuf_append_str (dbuf, "fixed16x16");
               break;
 
             case V_STRUCT:
-              fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
+              dbuf_printf (dbuf, "struct %s", SPEC_STRUCT (type)->tag);
               break;
 
             case V_SBIT:
-              fprintf (of, "sbit");
+              dbuf_append_str (dbuf, "sbit");
               break;
 
             case V_BIT:
-              fprintf (of, "bit");
+              dbuf_append_str (dbuf, "bit");
               break;
 
             case V_BITFIELD:
-              fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+              dbuf_printf (dbuf, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
               break;
 
             case V_DOUBLE:
-              fprintf (of, "double");
+              dbuf_append_str (dbuf, "double");
               break;
 
             default:
-              fprintf (of, "unknown type");
+              dbuf_append_str (dbuf, "unknown type");
               break;
             }
         }
@@ -2868,10 +2986,8 @@ printTypeChain (sym_link * start, FILE * of)
         search = search->next;
       type = search;
       if (type)
-        fputc (' ', of);
+          dbuf_append_char(dbuf, ' ');
     }
-  if (nlr)
-    fprintf (of, "\n");
 }
 
 /*--------------------------------------------------------------------*/
@@ -3053,7 +3169,7 @@ printTypeChainRaw (sym_link * start, FILE * of)
 /* powof2 - returns power of two for the number if number is pow 2 */
 /*-----------------------------------------------------------------*/
 int
-powof2 (TYPE_UDWORD num)
+powof2 (TYPE_TARGET_ULONG num)
 {
   int nshifts = 0;
   int n1s = 0;
@@ -3067,7 +3183,7 @@ powof2 (TYPE_UDWORD num)
     }
 
   if (n1s > 1 || nshifts == 0)
-    return 0;
+    return -1;
   return nshifts - 1;
 }
 
@@ -3384,17 +3500,50 @@ initCSupport ()
         {
           for (muldivmod = 1; muldivmod < 3; muldivmod++)
             {
-              /* div and mod */
-              SNPRINTF (buffer, sizeof(buffer),
-                        "_%s%s%s",
-                       smuldivmod[muldivmod],
-                       ssu[su],
-                       sbwd[bwd]);
-              __muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
-              FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+              /* div and mod : s8_t x s8_t -> s8_t should be s8_t x s8_t -> s16_t, see below */
+              if (!TARGET_IS_PIC16 || muldivmod != 1 || bwd != 0 || su != 0)
+              {
+                SNPRINTF (buffer, sizeof(buffer),
+                    "_%s%s%s",
+                    smuldivmod[muldivmod],
+                    ssu[su],
+                    sbwd[bwd]);
+                __muldiv[muldivmod][bwd][su] = funcOfType (
+                    _mangleFunctionName(buffer),
+                    __multypes[bwd][su],
+                    __multypes[bwd][su],
+                    2,
+                    options.intlong_rent);
+                FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+              }
             }
         }
     }
+
+  if (TARGET_IS_PIC16)
+  {
+    /* PIC16 port wants __divschar/__modschar to return an int, so that both
+     * 100 / -4 = -25 and -128 / -1 = 128 can be handled correctly
+     * (first one would have to be sign extended, second one must not be).
+     * Similarly, modschar should be handled, but the iCode introduces cast
+     * here and forces '% : s8 x s8 -> s8' ... */
+    su = 0; bwd = 0;
+    for (muldivmod = 1; muldivmod < 2; muldivmod++) {
+      SNPRINTF (buffer, sizeof(buffer),
+          "_%s%s%s",
+          smuldivmod[muldivmod],
+          ssu[su],
+          sbwd[bwd]);
+      __muldiv[muldivmod][bwd][su] = funcOfType (
+          _mangleFunctionName(buffer),
+          __multypes[1][su],
+          __multypes[bwd][su],
+          2,
+          options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+    }
+  }
+
   /* mul only */
   muldivmod = 0;
   /* byte */
@@ -3463,11 +3612,11 @@ void initBuiltIns()
     }
 }
 
-sym_link *validateLink(sym_link         *l, 
+sym_link *validateLink(sym_link         *l,
                         const char      *macro,
                         const char      *args,
                         const char      select,
-                        const char      *file, 
+                        const char      *file,
                         unsigned        line)
 {    
   if (l && l->class==select)
@@ -3479,7 +3628,7 @@ sym_link *validateLink(sym_link         *l,
             " expected %s, got %s\n",
             macro, args, file, line, 
             DECLSPEC2TXT(select), l ? DECLSPEC2TXT(l->class) : "null-link");
-    exit(-1);
+    exit(EXIT_FAILURE);
     return l; // never reached, makes compiler happy.
 }
 
@@ -3540,5 +3689,5 @@ newEnumType (symbol *enumlist)
         SPEC_USIGN (type) = 1;
     }
   
-  return type;    
+  return type;
 }