compiler/libec: (#316) Added missing edge on opaque structs
[sdk] / compiler / libec / src / pass15.ec
index 8a4f2a9..6eaa2bb 100644 (file)
@@ -84,7 +84,7 @@ bool NeedCast(Type type1, Type type2)
       return false;
    }
 
-   if(type1.kind == type2.kind)
+   if(type1.kind == type2.kind && type1.isLong == type2.isLong)
    {
       switch(type1.kind)
       {
@@ -1155,7 +1155,6 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
    External external = null;
    Symbol classSym = FindClass(name);
    OldList * curDeclarations = null;
-   Specifier curSpec = null;
 
    if(!inCompiler || !classSym) return null;
 
@@ -1175,7 +1174,6 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
       for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
          if(spec.type == structSpecifier || spec.type == unionSpecifier)
          {
-            curSpec = spec;
             curDeclarations = spec.definitions;
             break;
          }
@@ -1187,16 +1185,15 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
       OldList * declarations = null;
       char structName[1024];
       bool addedPadding = false;
+      Specifier curSpec = null;
 
       classSym.declaring++;
 
       if(strchr(classSym.string, '<'))
       {
          if(classSym.registered.templateClass)
-         {
             external = _DeclareStruct(neededBy, classSym.registered.templateClass.fullName, skipNoHead, needDereference, fwdDecl);
-            classSym.declaring--;
-         }
+         classSym.declaring--;
          return external;
       }
 
@@ -1222,6 +1219,18 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
             AddMembers(external, declarations, classSym.registered, false, null, classSym.registered, &addedPadding);
          }
 
+         if(external.declaration)
+         {
+            Specifier spec;
+            for(spec = external.declaration.specifiers ? external.declaration.specifiers->first : null; spec; spec = spec.next)
+               if(spec.type == structSpecifier || spec.type == unionSpecifier)
+               {
+                  curSpec = spec;
+                  curDeclarations = spec.definitions;
+                  break;
+               }
+         }
+
          if(declarations && (!declarations->count || (declarations->count == 1 && addedPadding)))
          {
             FreeList(declarations, FreeClassDef);
@@ -1240,10 +1249,6 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
                curSpec.definitions = declarations;
             else
             {
-               char className[1024];
-               strcpy(className, "__ecereClass_");
-               FullClassNameCat(className, classSym.string, true);
-
                specifiers = MkList();
                declarators = MkList();
                ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), declarations));
@@ -1280,6 +1285,18 @@ External _DeclareStruct(External neededBy, const char * name, bool skipNoHead, b
          external.symbol = classSym;
          ast->Add(external);
       }
+      if(reachedPass15 && !external.declaration && classSym.registered && classSym.registered.type == noHeadClass)
+      {
+         // Declare nohead classes without definitions here (e.g. IteratorPointer)
+         char structName[1024];
+         OldList * specifiers, * declarators;
+         structName[0] = 0;
+         FullClassNameCat(structName, name, false);
+         specifiers = MkList();
+         declarators = MkList();
+         ListAdd(specifiers, MkStructOrUnion(structSpecifier, MkIdentifier(structName), null));
+         external.declaration = MkDeclaration(specifiers, declarators);
+      }
       if(fwdDecl)
       {
          External e = external.fwdDecl ? external.fwdDecl : external;
@@ -3501,13 +3518,14 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
    Type source;
    Type realDest = dest;
    Type backupSourceExpType = null;
-   Expression computedExp = sourceExp;
+   Expression nbExp = GetNonBracketsExp(sourceExp);
+   Expression computedExp = nbExp;
    dest.refCount++;
 
    if(sourceExp.isConstant && sourceExp.type != constantExp && sourceExp.type != identifierExp && sourceExp.type != castExp &&
       dest.kind == classType && dest._class && dest._class.registered && dest._class.registered.type == enumClass)
    {
-      computedExp = CopyExpression(sourceExp);        // Keep the original expression, but compute for checking enum ranges
+      computedExp = CopyExpression(nbExp);        // Keep the original expression, but compute for checking enum ranges
       ComputeExpression(computedExp /*sourceExp*/);
    }
 
@@ -3515,10 +3533,10 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
 
    if(dest.kind == pointerType && sourceExp.type == constantExp && !strtoul(sourceExp.constant, null, 0))
    {
-      if(computedExp != sourceExp)
+      if(computedExp != nbExp)
       {
          FreeExpression(computedExp);
-         computedExp = sourceExp;
+         computedExp = nbExp;
       }
       FreeType(dest);
       return true;
@@ -3538,10 +3556,10 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
           //if(source._class.registered == dest._class.registered)
           if(sourceBase == destBase)
           {
-            if(computedExp != sourceExp)
+            if(computedExp != nbExp)
             {
                FreeExpression(computedExp);
-               computedExp = sourceExp;
+               computedExp = nbExp;
             }
             FreeType(dest);
             return true;
@@ -3571,14 +3589,14 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
          else
             value = -strtoull(computedExp.op.exp2.constant, null, 0);
       }
-      if(computedExp != sourceExp)
+      if(computedExp != nbExp)
       {
          FreeExpression(computedExp);
-         computedExp = sourceExp;
+         computedExp = nbExp;
       }
 
       if(dest.kind != classType && source.kind == classType && source._class && source._class.registered &&
-         !strcmp(source._class.registered.fullName, "ecere::com::unichar"))
+         !strcmp(source._class.registered.fullName, "unichar" /*"ecere::com::unichar"*/))
       {
          FreeType(source);
          source = Type { kind = intType, isSigned = false, refCount = 1 };
@@ -3695,7 +3713,7 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
       {
          Class _class = source._class ? source._class.registered : null;
 
-         if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || /*_class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
+         if(_class && (_class.type == unitClass || /*!strcmp(_class.fullName, "bool") || _class.type == enumClass || */_class.type == bitClass ))  // TOCHECK: enumClass, bitClass is new here...
          {
             /*
             if(dest.kind != classType)
@@ -3918,16 +3936,36 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
       else if(dest.kind == charType && (source.kind == _BoolType || source.kind == charType || source.kind == enumType || source.kind == shortType || source.kind == intType) &&
          (dest.isSigned ? (value >= -128 && value <= 127) : (value >= 0 && value <= 255)))
       {
-         specs = MkList();
-         if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
-         ListAdd(specs, MkSpecifier(CHAR));
+         if(source.kind == intType)
+         {
+            FreeType(dest);
+            FreeType(source);
+            if(backupSourceExpType) FreeType(backupSourceExpType);
+            return true;
+         }
+         else
+         {
+            specs = MkList();
+            if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
+            ListAdd(specs, MkSpecifier(CHAR));
+         }
       }
       else if(dest.kind == shortType && (source.kind == enumType || source.kind == _BoolType || source.kind == charType || source.kind == shortType ||
          (source.kind == intType && (dest.isSigned ? (value >= -32768 && value <= 32767) : (value >= 0 && value <= 65535)))))
       {
-         specs = MkList();
-         if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
-         ListAdd(specs, MkSpecifier(SHORT));
+         if(source.kind == intType)
+         {
+            FreeType(dest);
+            FreeType(source);
+            if(backupSourceExpType) FreeType(backupSourceExpType);
+            return true;
+         }
+         else
+         {
+            specs = MkList();
+            if(!dest.isSigned) ListAdd(specs, MkSpecifier(UNSIGNED));
+            ListAdd(specs, MkSpecifier(SHORT));
+         }
       }
       else if(dest.kind == intType && (source.kind == enumType || source.kind == shortType || source.kind == _BoolType || source.kind == charType || source.kind == intType))
       {
@@ -3998,10 +4036,10 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
    }
    else
    {
-      if(computedExp != sourceExp)
+      if(computedExp != nbExp)
       {
          FreeExpression(computedExp);
-         computedExp = sourceExp;
+         computedExp = nbExp;
       }
 
       while((sourceExp.type == bracketsExp || sourceExp.type == extensionExpressionExp) && sourceExp.list) sourceExp = sourceExp.list->last;
@@ -4088,7 +4126,7 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
    {                                                              \
       t value2 = op2.m;                                           \
       exp.type = constantExp;                                    \
-      exp.string = p(value2 ? (op1.m o value2) : 0);             \
+      exp.string = p(value2 ? ((t)(op1.m o value2)) : 0);             \
       if(!exp.expType) \
          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
       return true;                                                \
@@ -4099,7 +4137,7 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
    {                                                              \
       t value2 = op2.m;                                           \
       exp.type = constantExp;                                    \
-      exp.string = p(op1.m o value2);             \
+      exp.string = p((t)(op1.m o value2));             \
       if(!exp.expType) \
          { exp.expType = op1.type; if(op1.type) op1.type.refCount++; } \
       return true;                                                \
@@ -4391,7 +4429,12 @@ public Operand GetOperand(Expression exp)
                break;
             }
             case shortType:
-               if(type.isSigned)
+               if(exp.constant[0] == '\'')
+               {
+                  op.s = exp.constant[1];
+                  op.ops = shortOps;
+               }
+               else if(type.isSigned)
                {
                   op.s = (short)strtol(exp.constant, null, 0);
                   op.ops = shortOps;
@@ -4404,7 +4447,12 @@ public Operand GetOperand(Expression exp)
                break;
             case intType:
             case longType:
-               if(type.isSigned)
+               if(exp.constant[0] == '\'')
+               {
+                  op.i = exp.constant[1];
+                  op.ops = intOps;
+               }
+               else if(type.isSigned)
                {
                   op.i = (int)strtol(exp.constant, null, 0);
                   op.ops = intOps;
@@ -6632,15 +6680,16 @@ void CheckTemplateTypes(Expression exp)
                   break;
                }
             }
-            if(newExp.type == memberExp && newExp.member.memberType == dataMember)
+            /*if(newExp.type == memberExp && newExp.member.memberType == dataMember)
             {
+               // When was this required?    Removed to address using templated values to pass to printf()
                exp.type = opExp;
                exp.op.op = '*';
                exp.op.exp1 = null;
                exp.op.exp2 = MkExpCast(MkTypeName(MkListOne(MkSpecifierName("uint64")), MkDeclaratorPointer(MkPointer(null, null), null)),
                   MkExpBrackets(MkListOne(MkExpOp(null, '&', newExp))));
             }
-            else
+            else*/
             {
                char typeString[1024];
                Declarator decl;
@@ -6654,6 +6703,8 @@ void CheckTemplateTypes(Expression exp)
                exp.cast.typeName = MkTypeName(specs, decl);
                exp.cast.exp = MkExpBrackets(MkListOne(newExp));
                exp.cast.exp.needCast = true;
+               exp.needTemplateCast = 2;
+               newExp.needTemplateCast = 2;
             }
             break;
          }
@@ -6742,8 +6793,6 @@ static Symbol FindWithNameSpace(BinaryTree tree, const char * name)
    return null;
 }
 
-static void ProcessDeclaration(Declaration decl);
-
 /*static */Symbol FindSymbol(const char * name, Context startContext, Context endContext, bool isStruct, bool globalNameSpace)
 {
 #ifdef _DEBUG
@@ -8113,7 +8162,8 @@ void ProcessExpressionType(Expression exp)
                   char * endP = null;
                   int64 i64 = strtoll(constant, &endP, 0);
                   uint64 ui64 = strtoull(constant, &endP, 0);
-                  bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll"));
+                  bool is64Bit = endP && (!strcmp(endP, "LL") || !strcmp(endP, "ll") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
+                  bool forceUnsigned = endP && (!strcmp(endP, "U") || !strcmp(endP, "u") || !strcmp(endP, "LLU") || !strcmp(endP, "llu") || !strcmp(endP, "ull") || !strcmp(endP, "ULL"));
                   if(isSigned)
                   {
                      if(i64 < MININT)
@@ -8133,6 +8183,8 @@ void ProcessExpressionType(Expression exp)
                      else if(constant[0] != '0' || !constant[1])
                         isSigned = true;
                   }
+                  if(forceUnsigned)
+                     isSigned = false;
                   type.kind = is64Bit ? int64Type : intType;
                   type.isSigned = isSigned;
                }
@@ -8251,8 +8303,8 @@ void ProcessExpressionType(Expression exp)
 
             case LEFT_OP:
             case RIGHT_OP:
-               useSideType = true;
-               useDestType = true;
+               // useSideType = true;
+               // useDestType = true;
                break;
 
             case '|':
@@ -8353,6 +8405,17 @@ void ProcessExpressionType(Expression exp)
                FreeType(dummy);
                exp.op.exp1.destType = null;
             }
+
+            if(exp.op.exp2)
+            {
+               if(!assign && exp.op.exp1.expType && (exp.op.exp1.expType.kind == charType || exp.op.exp1.expType.kind == shortType))
+               {
+                  Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp1.expType.isSigned, bitMemberSize = exp.op.exp1.expType.bitMemberSize, promotedFrom = exp.op.exp1.expType.kind };
+                  FreeType(exp.op.exp1.expType);
+                  exp.op.exp1.expType = type;
+               }
+            }
+
             type1 = exp.op.exp1.expType;
          }
 
@@ -8462,6 +8525,16 @@ void ProcessExpressionType(Expression exp)
             exp.op.exp2.opDestType = false;
             if(exp.op.exp2.destType && exp.op.op != '=') exp.op.exp2.destType.count--;
 
+            if(!assign && (exp.op.exp1 || exp.op.op == '~'))
+            {
+               if(exp.op.exp2.expType && (exp.op.exp2.expType.kind == charType || exp.op.exp2.expType.kind == shortType))
+               {
+                  Type type { kind = intType, isSigned = true, refCount = 1, signedBeforePromotion = exp.op.exp2.expType.isSigned, bitMemberSize = exp.op.exp2.expType.bitMemberSize, promotedFrom = exp.op.exp2.expType.kind };
+                  FreeType(exp.op.exp2.expType);
+                  exp.op.exp2.expType = type;
+               }
+            }
+
             if(assign && type1 && type1.kind == pointerType && exp.op.exp2.expType)
             {
                if(exp.op.exp2.expType.kind == intSizeType || exp.op.exp2.expType.kind == intPtrType || exp.op.exp2.expType.kind == int64Type || exp.op.exp2.expType.kind == intType || exp.op.exp2.expType.kind == shortType || exp.op.exp2.expType.kind == charType)
@@ -8544,6 +8617,14 @@ void ProcessExpressionType(Expression exp)
          }
          else if(exp.op.op == '&' && !exp.op.exp1)
             exp.expType = Reference(type2);
+         else if(exp.op.op == LEFT_OP || exp.op.op == RIGHT_OP)
+         {
+            if(exp.op.exp1.expType)
+            {
+               exp.expType = exp.op.exp1.expType;
+               exp.expType.refCount++;
+            }
+         }
          else if(!assign)
          {
             if(boolOps)
@@ -10222,6 +10303,8 @@ void ProcessExpressionType(Expression exp)
                      member.dataType = ProcessTypeString(member.dataTypeString, false);
                      FinishTemplatesContext(context);
                   }
+                  if(exp.member.exp.expType.kind == classType && exp.member.exp.expType._class && exp.member.exp.expType._class.registered && exp.member.exp.expType._class.registered.type == bitClass)
+                     member.dataType.bitMemberSize = ((BitMember)member).size;
                   exp.expType = member.dataType;
                   if(member.dataType) member.dataType.refCount++;
                }
@@ -10319,6 +10402,10 @@ void ProcessExpressionType(Expression exp)
                         Type t = ProcessTypeString(exp.expType.templateParameter.dataTypeString, false);
                         if(t && t.kind == classType && t._class)
                            thisClassFrom = t._class.registered;
+                        else
+                           // Mark that 'thisClassFrom' was set to something
+                           thisClassFrom = eSystem_FindClass(GetPrivateModule(), "class");
+
                         FreeType(t);
 
                         passAsTemplate = tClass.templateClass && (exp.expType.kind != templateType ||
@@ -11086,6 +11173,16 @@ void ProcessExpressionType(Expression exp)
       }
    }
 
+   // Trying to do this here before conversion properties kick in and this becomes a new expression... (Fixing Class c; const char * a = c;)
+   // Mark nohead classes as by reference, unless we're casting them to an integral type
+   if(!notByReference && exp.expType && exp.expType.kind == classType && exp.expType._class && exp.expType._class.registered &&
+      exp.expType._class.registered.type == noHeadClass && (!exp.destType ||
+         (exp.destType.kind != intType && exp.destType.kind != int64Type && exp.destType.kind != intPtrType && exp.destType.kind != intSizeType &&
+          exp.destType.kind != longType && exp.destType.kind != shortType && exp.destType.kind != charType && exp.destType.kind != _BoolType)))
+   {
+      exp.byReference = true;
+   }
+
    yylloc = exp.loc;
    if(exp.destType && (/*exp.destType.kind == voidType || */exp.destType.kind == dummyType) );
    else if(exp.destType && !exp.destType.keepCast)
@@ -11161,23 +11258,115 @@ void ProcessExpressionType(Expression exp)
                   (exp.expType.kind != classType || exp.expType.classObjectType || (exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type != structClass)));
                else
                {
-                  char expString[10240];
-                  expString[0] = '\0';
-                  if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
+                  Expression nbExp = GetNonBracketsExp(exp);
+                  bool skipWarning = false;
+                  TypeKind kind = exp.destType.kind;
+                  if(nbExp.type == conditionExp && !nbExp.destType.casted && nbExp.destType.kind == exp.destType.kind)
+                     // The if/else operands have already been checked / warned about
+                     skipWarning = true;
+                  if((kind == charType || kind == shortType) && exp.destType.isSigned == exp.expType.signedBeforePromotion && nbExp.type == opExp && nbExp.op.exp1 && nbExp.op.exp2)
+                  {
+                     int op = nbExp.op.op;
+                     Expression nbExp1, nbExp2;
+                     TypeKind from;
+
+                     switch(op)
+                     {
+                        case '%': case '/':
+                           nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
+                           from = nbExp1.expType.promotedFrom;
+                           // Division and Modulo will not take more room than type before promotion
+                           if(from == charType || (kind == shortType && from == shortType))
+                              skipWarning = true;
+                           break;
+                        // Left shift
+                        case LEFT_OP: case RIGHT_OP:
+                           nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
+                           nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
+                           from = nbExp1.expType.promotedFrom;
+                           // Right shift will not take more room than type before promotion
+                           if(op == RIGHT_OP && (from == charType || (kind == shortType && from == shortType)))
+                              skipWarning = true;
+                           else if(nbExp2.isConstant && nbExp2.type == constantExp && (nbExp.op.op == RIGHT_OP || nbExp1.expType.bitMemberSize))
+                           {
+                              int n = (int)strtol(nbExp2.constant, null, 0);
+                              int s = from == charType ? 8 : 16;
+                              // Left shifting a bit member constrained in size may still fit in type before promotion
+                              if(nbExp1.expType.bitMemberSize && nbExp1.expType.bitMemberSize < s)
+                                 s = nbExp1.expType.bitMemberSize;
+
+                              // If right shifted enough things will fit in smaller type
+                              if(nbExp.op.op == RIGHT_OP)
+                                 s -= n;
+                              else
+                                 s += n;
+                              if(s <= (kind == charType ? 8 : 16))
+                                 skipWarning = true;
+                           }
+                           break;
+                        case '-':
+                           if(!exp.destType.isSigned)
+                           {
+                              nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
+                              nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
+                              from = nbExp2.expType.promotedFrom;
+                              // Max value of unsigned type before promotion minus the same will always fit
+                              if((from == charType || from == shortType) && nbExp1.isConstant && nbExp1.type == constantExp)
+                              {
+                                 int n = (int)strtol(nbExp1.constant, null, 0);
+                                 if(n == (from == charType ? 255 : 65535))
+                                    skipWarning = true;
+                              }
+                           }
+                           break;
+                        case '|':
+                        {
+                           TypeKind kind1, kind2;
+                           nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
+                           nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
+                           kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
+                           kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
+                           if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) &&
+                              ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
+                              skipWarning = true;
+                           break;
+                        }
+                        case '&':
+                        {
+                           TypeKind kind1, kind2;
+                           nbExp1 = GetNonBracketsExp(nbExp.op.exp1);
+                           nbExp2 = GetNonBracketsExp(nbExp.op.exp2);
+                           kind1 = nbExp1.expType.promotedFrom ? nbExp1.expType.promotedFrom : nbExp1.expType.kind;
+                           kind2 = nbExp2.expType.promotedFrom ? nbExp2.expType.promotedFrom : nbExp2.expType.kind;
+                           if(((kind1 == charType || (kind1 == shortType && kind == shortType)) || MatchTypeExpression(nbExp1, exp.destType, null, false, false)) ||
+                              ((kind2 == charType || (kind2 == shortType && kind == shortType)) || MatchTypeExpression(nbExp2, exp.destType, null, false, false)))
+                              skipWarning = true;
+                           break;
+                        }
+                     }
+                  }
+
+                  if(!skipWarning)
+                  {
+                     char expString[10240];
+                     expString[0] = '\0';
+                     if(inCompiler) { PrintExpression(exp, expString); ChangeCh(expString, '\n', ' '); }
 
 #ifdef _DEBUG
-                  CheckExpressionType(exp, exp.destType, false, true);
+                     CheckExpressionType(exp, exp.destType, false, true);
 #endif
-                  // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
-                  if(!sourceFile || (!strstr(sourceFile, "src\\lexer.ec") && !strstr(sourceFile, "src/lexer.ec") &&
-                                     !strstr(sourceFile, "src\\grammar.ec") && !strstr(sourceFile, "src/grammar.ec") &&
-                                     !strstr(sourceFile, "src\\type.ec") && !strstr(sourceFile, "src/type.ec") &&
-                                     !strstr(sourceFile, "src\\expression.ec") && !strstr(sourceFile, "src/expression.ec")))
-                  {
-                     if(invalidCast)
-                        Compiler_Error($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
-                     else
-                        Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
+
+                     // Flex & Bison generate code that triggers this, so we ignore it for a quiet sdk build:
+                     if(!sourceFile || (!strstr(sourceFile, "src\\lexer.ec") && !strstr(sourceFile, "src/lexer.ec") &&
+                                        !strstr(sourceFile, "src\\grammar.ec") && !strstr(sourceFile, "src/grammar.ec") &&
+                                        !strstr(sourceFile, "src\\type.ec") && !strstr(sourceFile, "src/type.ec") &&
+                                        !strstr(sourceFile, "src\\expression.ec") && !strstr(sourceFile, "src/expression.ec")))
+                     {
+                        if(invalidCast)
+                           Compiler_Error($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
+                        else
+                           Compiler_Warning($"incompatible expression %s (%s); expected %s\n", expString, type1, type2);
+                     }
                   }
 
                   // TO CHECK: FORCING HERE TO HELP DEBUGGER
@@ -11398,7 +11587,7 @@ static void ProcessInitializer(Initializer init, Type type)
    }
 }
 
-static void ProcessSpecifier(Specifier spec, bool declareStruct)
+static void ProcessSpecifier(Specifier spec, bool declareStruct, bool warnClasses)
 {
    switch(spec.type)
    {
@@ -11411,7 +11600,7 @@ static void ProcessSpecifier(Specifier spec, bool declareStruct)
                spec.type = nameSpecifier;
                spec.name = ReplaceThisClass(thisClass);
                spec.symbol = FindClass(spec.name);
-               ProcessSpecifier(spec, declareStruct);
+               ProcessSpecifier(spec, declareStruct, false);
             }
          }
          break;
@@ -11424,6 +11613,8 @@ static void ProcessSpecifier(Specifier spec, bool declareStruct)
          else if(spec.symbol /*&& declareStruct*/)
          {
             Class c = spec.symbol.registered;
+            if(warnClasses && !c)
+               Compiler_Warning("Undeclared class %s\n", spec.name);
             DeclareStruct(curExternal, spec.name, c && c.type == noHeadClass, declareStruct && c && c.type == structClass);
          }
          break;
@@ -11544,7 +11735,7 @@ static void ProcessDeclarator(Declarator decl, bool isFunction)
                                  qualifiers = MkListOne(MkSpecifier(VOID));
                                  declarator = MkDeclaratorPointer(MkPointer(null,null), d);
                               };
-                              if(d.type != pointerDeclarator)
+                              if(!d || d.type != pointerDeclarator)
                                  newParam.qualifiers->Insert(null, MkSpecifier(CONST));
 
                               FreeList(param.qualifiers, FreeSpecifier);
@@ -11565,7 +11756,7 @@ static void ProcessDeclarator(Declarator decl, bool isFunction)
                               FreeList(param.qualifiers, FreeSpecifier);
 
                               param.qualifiers = MkListOne(MkSpecifier(VOID));
-                              if(d.type != pointerDeclarator)
+                              if(!d || d.type != pointerDeclarator)
                                  param.qualifiers->Insert(null, MkSpecifier(CONST));
                               param.declarator = MkDeclaratorPointer(MkPointer(null,null), d);
                               break;
@@ -11577,14 +11768,20 @@ static void ProcessDeclarator(Declarator decl, bool isFunction)
                                  spec.type = nameSpecifier;
                                  spec.name = ReplaceThisClass(thisClass);
                                  spec.symbol = FindClass(spec.name);
-                                 ProcessSpecifier(spec, false);
+                                 ProcessSpecifier(spec, false, false);
                               }
                               break;
                            }
                         }
                         else if(spec.type == nameSpecifier)
                         {
-                           ProcessSpecifier(spec, isFunction);
+                           ProcessSpecifier(spec, isFunction, true);
+                        }
+                        else if((spec.type == structSpecifier || spec.type == unionSpecifier) && !spec.definitions && spec.id && spec.id.string)
+                        {
+                           Declarator d = param.declarator;
+                           if(!d || d.type != pointerDeclarator)
+                              DeclareStruct(curExternal, spec.id.string, false, true);
                         }
                      }
                   }
@@ -11599,7 +11796,7 @@ static void ProcessDeclarator(Declarator decl, bool isFunction)
    }
 }
 
-static void ProcessDeclaration(Declaration decl)
+static void ProcessDeclaration(Declaration decl, bool warnClasses)
 {
    yylloc = decl.loc;
    switch(decl.type)
@@ -11675,7 +11872,7 @@ static void ProcessDeclaration(Declaration decl)
             Specifier s;
             for(s = decl.specifiers->first; s; s = s.next)
             {
-               ProcessSpecifier(s, declareStruct);
+               ProcessSpecifier(s, declareStruct, true);
             }
          }
          break;
@@ -11718,7 +11915,7 @@ static void ProcessDeclaration(Declaration decl)
          if(decl.specifiers)
          {
             for(spec = decl.specifiers->first; spec; spec = spec.next)
-               ProcessSpecifier(spec, declareStruct);
+               ProcessSpecifier(spec, declareStruct, warnClasses);
          }
          break;
       }
@@ -11822,7 +12019,7 @@ static void ProcessStatement(Statement stmt)
             if(stmt.compound.declarations)
             {
                for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
-                  ProcessDeclaration(decl);
+                  ProcessDeclaration(decl, true);
             }
             if(stmt.compound.statements)
             {
@@ -12353,7 +12550,7 @@ static void ProcessStatement(Statement stmt)
                }
                ProcessExpressionType(expIt);
                if(stmt.compound.declarations->first)
-                  ProcessDeclaration(stmt.compound.declarations->first);
+                  ProcessDeclaration(stmt.compound.declarations->first, true);
 
                if(symbol)
                   symbol.isIterator = isMap ? 2 : ((isArray || isBuiltin) ? 3 : (isLinkList ? (isList ? 5 : 4) : (isCustomAVLTree ? 6 : 1)));
@@ -12402,7 +12599,7 @@ static void ProcessStatement(Statement stmt)
       }
       case badDeclarationStmt:
       {
-         ProcessDeclaration(stmt.decl);
+         ProcessDeclaration(stmt.decl, true);
          break;
       }
       case asmStmt:
@@ -12474,15 +12671,15 @@ static void ProcessStatement(Statement stmt)
 
                   if(object && object.expType && object.expType.kind == classType && object.expType._class && object.expType._class.registered)
                   {
-                     // TESTING THIS STUFF... BEWARE OF SYMBOL ID ISSUES
                      func = MkClassFunction(MkListOne(MkSpecifier(VOID)), null, MkDeclaratorFunction(MkDeclaratorIdentifier(MkIdentifier(watcherName)),
-                        //MkListOne(MkTypeName(MkListOne(MkSpecifier(VOID)), null))), null);
                         MkListOne(MkTypeName(MkListOne(MkSpecifierName(object.expType._class.string)), MkDeclaratorIdentifier(MkIdentifier("value"))))), null);
                      ProcessClassFunctionBody(func, propWatch.compound);
                      propWatch.compound = null;
 
                      createdExternal = ProcessClassFunction(watcherClass, func, ast, curExternal, true);
 
+                     FreeClassFunction(func);
+
                      curExternal = createdExternal;
                      ProcessFunction(createdExternal.function);
 
@@ -13063,7 +13260,7 @@ static void ProcessClass(OldList definitions, Symbol symbol)
          {
             Class backThisClass = thisClass;
             if(regClass) thisClass = regClass;
-            ProcessDeclaration(def.decl);
+            ProcessDeclaration(def.decl, symbol ? true : false);
             thisClass = backThisClass;
          }
       }
@@ -13182,6 +13379,8 @@ void DeclareFunctionUtil(External neededBy, const String s)
       FindSymbol(s, globalContext, globalContext, false, false);
 }
 
+bool reachedPass15;
+
 void ComputeDataTypes()
 {
    External external;
@@ -13211,6 +13410,7 @@ void ComputeDataTypes()
    DeclareFunctionUtil(null, "eInstance_StopWatching");
    DeclareFunctionUtil(null, "eInstance_Watch");
    DeclareFunctionUtil(null, "eInstance_FireWatchers");
+   reachedPass15 = true;
 
    for(external = ast->first; external; external = external.next)
    {
@@ -13237,7 +13437,7 @@ void ComputeDataTypes()
 
          currentClass = null;
          if(external.declaration)
-            ProcessDeclaration(external.declaration);
+            ProcessDeclaration(external.declaration, true);
       }
       else if(external.type == classExternal)
       {