compiler: (WIP) Fixes for MinGW/GCC 5
[sdk] / compiler / libec / src / pass15.ec
index 8a4f2a9..cc4aaef 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)
       {
@@ -121,6 +121,7 @@ static void ReplaceClassMembers(Expression exp, Class _class)
          // First, check if the identifier is declared inside the function
          for(ctx = curContext; ctx != topContext.parent && !symbol; ctx = ctx.parent)
          {
+            if(!ctx) break;   // This happened opening old mapTileCache.ec from archives?
             symbol = (Symbol)ctx.symbols.FindString(id.string);
             if(symbol) break;
          }
@@ -666,7 +667,9 @@ void ComputeClassMembers(Class _class, bool isMember)
                if(_class.memberOffset % _class.structAlignment)
                   extra += _class.structAlignment - (_class.memberOffset % _class.structAlignment);
             }
-            _class.structSize = (_class.base ? (_class.base.templateClass ? _class.base.templateClass.structSize : _class.base.structSize) : 0) + _class.memberOffset + extra;
+            _class.structSize = (_class.base ? (_class.base.templateClass ?
+               (_class.base.type == noHeadClass ? _class.base.templateClass.memberOffset : _class.base.templateClass.structSize) :
+                  (_class.base.type == noHeadClass ? _class.base.memberOffset : _class.base.structSize) ) : 0) + _class.memberOffset + extra;
             if(!member)
             {
                Property prop;
@@ -690,7 +693,7 @@ void ComputeClassMembers(Class _class, bool isMember)
                   if(deriv.computeSize)
                   {
                      // TESTING THIS NEW CODE HERE... TRYING TO FIX ScrollBar MEMBERS DEBUGGING
-                     deriv.offset = /*_class.offset + */_class.structSize;
+                     deriv.offset = /*_class.offset + */(_class.type == noHeadClass ? _class.memberOffset : _class.structSize);
                      deriv.memberOffset = 0;
                      // ----------------------
 
@@ -1155,7 +1158,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 +1177,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 +1188,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 +1222,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 +1252,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 +1288,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;
@@ -1609,7 +1629,13 @@ public Type Dereference(Type source)
    Type type = null;
    if(source)
    {
-      if(source.kind == pointerType || source.kind == arrayType)
+      if(source.isVector)
+      {
+         type = { refCount = 1 };
+         CopyTypeInto(type, source);
+         type.isVector = false;
+      }
+      else if(source.kind == pointerType || source.kind == arrayType)
       {
          type = source.type;
          source.type.refCount++;
@@ -2196,7 +2222,7 @@ static void _DeclareType(External neededFor, Type type, bool needDereference, bo
          _DeclareType(neededFor, type.type, false, false, fwdDecl);
       else if(type.kind == classType)
       {
-         Class c = type._class.registered;
+         Class c = type._class ? type._class.registered : null;
          _DeclareStruct(neededFor, c ? c.fullName : "ecere::com::Instance", c ? c.type == noHeadClass : false, needDereference && c && c.type == structClass, fwdDecl);
       }
       else if(type.kind == structType || type.kind == unionType)
@@ -2952,9 +2978,11 @@ public bool MatchTypes(Type source, Type dest, OldList conversions, Class owning
          else
          {
             // Added this so that DefinedColor = Color doesn't go through ColorRGB property
-            if(enumBaseType &&
-               dest._class && dest._class.registered && dest._class.registered.type == enumClass &&
-               ((source._class && source._class.registered && source._class.registered.type != enumClass) || source.kind == classType)) // Added this here for a base enum to be acceptable for a derived enum (#139)
+            if(dest._class && dest._class.registered && source._class && source._class.registered &&
+               (dest.casted || (enumBaseType && dest._class.registered.type == enumClass &&
+                  (source.kind == classType ||  // Added this here for a base enum to be acceptable for a derived enum (#139)
+                   source._class.registered.type != enumClass)
+                ) ) )
             {
                if(eClass_IsDerived(dest._class.registered, source._class.registered))
                {
@@ -3167,6 +3195,8 @@ public bool MatchTypes(Type source, Type dest, OldList conversions, Class owning
          return true;
       else if(dest.kind == int64Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == intSizeType))
          return true;
+      else if(dest.kind == int128Type && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intPtrType || source.kind == int64Type || source.kind == intSizeType))
+         return true;
       else if(dest.kind == intPtrType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == intSizeType || source.kind == int64Type))
          return true;
       else if(dest.kind == intSizeType && (source.kind == shortType || source.kind == charType || source.kind == _BoolType || source.kind == intType || source.kind == int64Type || source.kind == intPtrType))
@@ -3501,13 +3531,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 +3546,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 +3569,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;
@@ -3564,21 +3595,21 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
          else
             value = strtoull(computedExp.constant, null, 0);
       }
-      else if(computedExp.type == opExp && sourceExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
+      else if(computedExp.type == opExp && computedExp.op.op == '-' && !computedExp.op.exp1 && computedExp.op.exp2 && computedExp.op.exp2.type == constantExp)
       {
          if(source.isSigned)
             value = -strtoll(computedExp.op.exp2.constant, null, 0);
          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 +3726,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)
@@ -3735,6 +3766,9 @@ bool MatchTypeExpression(Expression sourceExp, Type dest, OldList conversions, b
                {
                   ((Conversion)(conversions.last)).resultType = dest;
                   dest.refCount++;
+
+                  // This fixes passing unit as template to a double
+                  modifyPassAsTemplate(&((Conversion)(conversions.last)).resultType, false);
                }
 
                FreeType(sourceExp.expType);
@@ -3918,16 +3952,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 +4052,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 +4142,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 +4153,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;                                                \
@@ -4349,7 +4403,7 @@ public Operand GetOperand(Expression exp)
    Type type = exp.expType;
    if(type)
    {
-      while(type.kind == classType &&
+      while(type.kind == classType && type._class &&
          type._class.registered && (type._class.registered.type == bitClass || type._class.registered.type == unitClass || type._class.registered.type == enumClass))
       {
          if(!type._class.registered.dataType)
@@ -4391,7 +4445,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 +4463,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;
@@ -5672,6 +5736,14 @@ void ComputeExpression(Expression exp)
                OldList * list = exp.list;
                Expression prev = exp.prev;
                Expression next = exp.next;
+
+               // For operations which set the exp type on brackets exp after the inner exp was processed...
+               if(exp.expType && exp.expType.kind == classType && (!e.expType || e.expType.kind != classType))
+               {
+                  FreeType(e.expType);
+                  e.expType = exp.expType;
+                  e.expType.refCount++;
+               }
                ComputeExpression(e);
                //FreeExpContents(exp);
                FreeType(exp.expType);
@@ -6467,6 +6539,18 @@ static bool CheckExpressionType(Expression exp, Type destType, bool skipUnitBla,
    return result;
 }
 
+void modifyPassAsTemplate(Type * typePtr, bool value)
+{
+   if(*typePtr && typePtr->passAsTemplate != value)
+   {
+      Type type { refCount = 1 };
+      CopyTypeInto(type, *typePtr);
+      type.passAsTemplate = value;
+      FreeType(*typePtr);
+      *typePtr = type;
+   }
+}
+
 void CheckTemplateTypes(Expression exp)
 {
    /*
@@ -6509,8 +6593,8 @@ void CheckTemplateTypes(Expression exp)
             }
             else
             {
-               // If we're looking for value:
-               // ({ union { double d; uint64 i; } u; u.i = [newExp]; u.d; })
+               // We want to pass as a template argument
+               // ({ union { double d; uint64 i; } u; u.d = [newExp]; u.i; })
                OldList * specs;
                OldList * unionDefs = MkList();
                OldList * statements = MkList();
@@ -6519,6 +6603,11 @@ void CheckTemplateTypes(Expression exp)
                ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
                exp.type = extensionCompoundExp;
+
+               modifyPassAsTemplate(&exp.expType, true);
+               modifyPassAsTemplate(&newExp.destType, false);
+               modifyPassAsTemplate(&newExp.expType, false);
+
                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")), '=', newExp))));
                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
@@ -6526,6 +6615,41 @@ void CheckTemplateTypes(Expression exp)
                PopContext(context);
             }
             break;
+         case floatType:
+            if(exp.destType.classObjectType)
+            {
+               // We need to pass the address, just pass it along (Undo what was done above)
+               if(exp.destType) exp.destType.refCount--;
+               if(exp.expType)  exp.expType.refCount--;
+               delete newExp;
+            }
+            else
+            {
+               // We want to pass as a template argument
+               // ({ union { float f; uint64 i; } u; u.f = [newExp]; u.i; })
+               OldList * specs;
+               OldList * unionDefs = MkList();
+               OldList * statements = MkList();
+               context = PushContext();
+               ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(FLOAT)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("f"))), null)));
+               ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
+               specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
+               exp.type = extensionCompoundExp;
+               exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
+
+               modifyPassAsTemplate(&exp.expType, true);
+               modifyPassAsTemplate(&newExp.destType, false);
+               modifyPassAsTemplate(&newExp.expType, false);
+
+               ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("f")), '=', newExp))));
+               ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")))));
+               exp.compound.compound.context = context;
+               PopContext(context);
+            }
+            break;
+         case voidType:
+            // Generated code already processed...
+            break;
          default:
             exp.type = castExp;
             exp.cast.typeName = MkTypeName(MkListOne(MkSpecifierName("uint64")), null);
@@ -6582,12 +6706,49 @@ void CheckTemplateTypes(Expression exp)
                specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
                exp.type = extensionCompoundExp;
                exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
+
+               modifyPassAsTemplate(&exp.expType, false);
+               modifyPassAsTemplate(&newExp.destType, true);
+               modifyPassAsTemplate(&newExp.expType, true);
+
                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
                ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("d")))));
                exp.compound.compound.context = context;
                PopContext(context);
             }
             break;
+         case floatType:
+            if(exp.destType.classObjectType)
+            {
+               // We need to pass the address, just pass it along (Undo what was done above)
+               if(exp.destType) exp.destType.refCount--;
+               if(exp.expType)  exp.expType.refCount--;
+               delete newExp;
+            }
+            else
+            {
+               // If we're looking for value:
+               // ({ union { float f; uint64 i; } u; u.i = [newExp]; u.f; })
+               OldList * specs;
+               OldList * unionDefs = MkList();
+               OldList * statements = MkList();
+               context = PushContext();
+               ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifier(FLOAT)), MkListOne(MkDeclaratorIdentifier(MkIdentifier("f"))), null)));
+               ListAdd(unionDefs, MkClassDefDeclaration(MkStructDeclaration(MkListOne(MkSpecifierName("uint64")), MkListOne(MkDeclaratorIdentifier(MkIdentifier("i"))), null)));
+               specs = MkListOne(MkStructOrUnion(unionSpecifier, null, unionDefs ));
+               exp.type = extensionCompoundExp;
+               exp.compound = MkCompoundStmt(MkListOne(MkDeclaration(specs, MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("__internal_union")), null)))),statements);
+
+               modifyPassAsTemplate(&exp.expType, false);
+               modifyPassAsTemplate(&newExp.destType, true);
+               modifyPassAsTemplate(&newExp.expType, true);
+
+               ListAdd(statements, MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("i")), '=', newExp))));
+               ListAdd(statements, MkExpressionStmt(MkListOne(MkExpMember(MkExpIdentifier(MkIdentifier("__internal_union")), MkIdentifier("f")))));
+               exp.compound.compound.context = context;
+               PopContext(context);
+            }
+            break;
          case classType:
          {
             if(exp.expType._class && exp.expType._class.registered && exp.expType._class.registered.type == structClass)
@@ -6632,15 +6793,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 +6816,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 +6906,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
@@ -6807,6 +6969,7 @@ static void GetTypeSpecs(Type type, OldList * specs)
       case _BoolType: ListAdd(specs, MkSpecifier(_BOOL)); break;
       case shortType: ListAdd(specs, MkSpecifier(SHORT)); break;
       case int64Type: ListAdd(specs, MkSpecifier(INT64)); break;
+      case int128Type: ListAdd(specs, MkSpecifier(INT128)); break;
       case intPtrType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intptr" : "uintptr")); break;
       case intSizeType: ListAdd(specs, MkSpecifierName(type.isSigned ? "intsize" : "uintsize")); break;
       case intType:
@@ -6859,6 +7022,7 @@ static void PrintTypeSpecs(Type type, char * string, bool fullName, bool printCo
          case voidType: strcat(string, "void"); break;
          case intType:  strcat(string, type.isSigned ? "int" : "uint"); break;
          case int64Type:  strcat(string, type.isSigned ? "int64" : "uint64"); break;
+         case int128Type:  strcat(string, type.isSigned ? "__int128" : "unsigned __int128"); break;
          case intPtrType:  strcat(string, type.isSigned ? "intptr" : "uintptr"); break;
          case intSizeType:  strcat(string, type.isSigned ? "intsize" : "uintsize"); break;
          case charType: strcat(string, type.isSigned ? "char" : "byte"); break;
@@ -7714,6 +7878,13 @@ void ApplyLocation(Expression exp, Location loc)
    }
 }
 
+bool RelatedUnits(Class c1, Class c2)
+{
+   if(c1.base.type == unitClass) c1 = c1.base;
+   if(c2.base.type == unitClass) c2 = c2.base;
+   return c1 == c2;
+}
+
 void ProcessExpressionType(Expression exp)
 {
    bool unresolved = false;
@@ -7779,7 +7950,13 @@ void ProcessExpressionType(Expression exp)
          }
          else
          {
-            Symbol symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
+            Symbol symbol = null;
+            bool findInGlobal = false;
+            if(!topContext.parent && exp.destType && exp.destType.kind == classType && exp.destType._class && exp.destType._class.registered && exp.destType._class.registered.type == enumClass)
+               findInGlobal = true;  // In global context, look at enum values first
+            else
+               symbol = FindSymbol(id.string, curContext, topContext /*exp.destType ? topContext : globalContext*/, false, id._class && id._class.name == null);
+
             // Enums should be resolved here (Special pass in opExp to fix identifiers not seen as enum on the first pass)
             if(!symbol/* && exp.destType*/)
             {
@@ -7805,6 +7982,8 @@ void ProcessExpressionType(Expression exp)
                   symbol = FindSymbol(id.string, topContext.parent, globalContext, false, id._class && id._class.name == null);
                }
             }
+            if(findInGlobal)
+               symbol = FindSymbol(id.string, curContext, topContext, false, id._class && id._class.name == null);
 
             // If we manage to resolve this symbol
             if(symbol)
@@ -8113,7 +8292,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 +8313,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;
                }
@@ -8195,6 +8377,8 @@ void ProcessExpressionType(Expression exp)
          Location oldyylloc = yylloc;
          bool useSideUnit = false;
          Class destClass = (exp.destType && exp.destType.kind == classType && exp.destType._class) ? exp.destType._class.registered : null;
+         bool powerOp = false, relationOp = false;
+         Class c1 = null, c2 = null;
 
          // Dummy type to prevent ProcessExpression of operands to say unresolved identifiers yet
          Type dummy
@@ -8241,6 +8425,7 @@ void ProcessExpressionType(Expression exp)
                // Gives boolean result
                boolResult = true;
                useSideType = true;
+               relationOp = true;
                break;
             case '+':
             case '-':
@@ -8251,8 +8436,8 @@ void ProcessExpressionType(Expression exp)
 
             case LEFT_OP:
             case RIGHT_OP:
-               useSideType = true;
-               useDestType = true;
+               // useSideType = true;
+               // useDestType = true;
                break;
 
             case '|':
@@ -8265,6 +8450,7 @@ void ProcessExpressionType(Expression exp)
             case '%':
                useSideType = true;
                useDestType = true;
+               if(exp.op.op == '/') powerOp = true;
                break;
             case '&':
             case '*':
@@ -8273,6 +8459,7 @@ void ProcessExpressionType(Expression exp)
                   // For & operator, useDestType nicely ensures the result will fit in a bool (TODO: Fix for generic enum)
                   useSideType = true;
                   useDestType = true;
+                  if(exp.op.op == '*') powerOp = true;
                }
                break;
 
@@ -8330,6 +8517,17 @@ void ProcessExpressionType(Expression exp)
                if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
                exp.op.exp1.destType = dummy;
                dummy.refCount++;
+               if(powerOp)
+                  exp.op.exp1.opDestType = true;
+               if(relationOp)
+                  exp.op.exp1.usedInComparison = true;
+            }
+            if(exp.op.op == '+' || exp.op.op == '-')
+            {
+               if(exp.opDestType)
+                  exp.op.exp1.parentOpDestType = true;
+               if(exp.usedInComparison)
+                  exp.op.exp1.usedInComparison = true;
             }
 
             // TESTING THIS HERE...
@@ -8338,6 +8536,7 @@ void ProcessExpressionType(Expression exp)
             if(exp.op.exp1.destType && exp.op.op != '=') exp.op.exp1.destType.count--;
 
             exp.op.exp1.opDestType = false;
+            exp.op.exp1.usedInComparison = false;
 
             // Fix for unit and ++ / --
             if(!exp.op.exp2 && (exp.op.op == INC_OP || exp.op.op == DEC_OP) && exp.op.exp1.expType && exp.op.exp1.expType.kind == classType &&
@@ -8353,6 +8552,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;
          }
 
@@ -8430,6 +8640,10 @@ void ProcessExpressionType(Expression exp)
                if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
                exp.op.exp2.destType = dummy;
                dummy.refCount++;
+               if(powerOp)
+                  exp.op.exp2.opDestType = true;
+               if(relationOp)
+                  exp.op.exp2.usedInComparison = true;
             }
 
             // TESTING THIS HERE... (DANGEROUS)
@@ -8458,10 +8672,28 @@ void ProcessExpressionType(Expression exp)
                if(e.type == castExp && e.cast.exp)
                   e.cast.exp.needCast = true;
             }
+            if(exp.op.op == '+' || exp.op.op == '-')
+            {
+               if(exp.opDestType)
+                  exp.op.exp2.parentOpDestType = true;
+               if(exp.usedInComparison)
+                  exp.op.exp2.usedInComparison = true;
+            }
             ProcessExpressionType(exp.op.exp2);
             exp.op.exp2.opDestType = false;
+            exp.op.exp2.usedInComparison = 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)
@@ -8523,6 +8755,24 @@ void ProcessExpressionType(Expression exp)
                if(type2) type2.refCount++;
             }
          }
+         c1 = type1 && type1.kind == classType && type1._class ? type1._class.registered : null;
+         c2 = type2 && type2.kind == classType && type2._class ? type2._class.registered : null;
+
+         if(relationOp &&
+            ( (exp.op.exp1 && exp.op.exp1.ambiguousUnits && (!c2 || c2.type != unitClass)) ||
+               (exp.op.exp2 && exp.op.exp2.ambiguousUnits && (!c1 || c1.type != unitClass))) )
+            Compiler_Warning($"ambiguous units in relational operation\n");
+
+         if(!relationOp &&
+            ((exp.op.exp1 && exp.op.exp1.ambiguousUnits) ||
+             (exp.op.exp2 && exp.op.exp2.ambiguousUnits)) &&
+             (!powerOp || !c1 || c1.type != unitClass || !c2 || c2.type != unitClass || !RelatedUnits(c1, c2)))
+         {
+            if(exp.opDestType || exp.usedInComparison)
+               exp.ambiguousUnits = true;
+            else
+               Compiler_Warning($"ambiguous units\n");
+         }
 
          dummy.kind = voidType;
 
@@ -8544,8 +8794,21 @@ 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(c1 && !c1.dataType)
+               c1.dataType = ProcessTypeString(c1.dataTypeString, false);
+            if(c2 && !c2.dataType)
+               c2.dataType = ProcessTypeString(c2.dataTypeString, false);
+
             if(boolOps)
             {
                if(exp.op.exp1)
@@ -8575,11 +8838,33 @@ void ProcessExpressionType(Expression exp)
                   exp.op.exp2.expType.truth = true;
                }
             }
+            else if(powerOp && exp.op.exp1 && exp.op.exp2 && ((c1 && c1.type == unitClass) || (c2 && c2.type == unitClass)))
+            {
+               // * or / with at least one unit operand
+               if(c1 && c1.type == unitClass && c2 && c2.type == unitClass)
+               {
+                  // This is where we'd handle unit powers e.g. square meters or meters/seconds
+                  // For now using base types
+                  if(c1.dataType.kind == doubleType)        exp.expType = c1.dataType;
+                  else if(c2.dataType.kind == doubleType)   exp.expType = c2.dataType;
+                  else if(c1.dataType.kind == floatType)    exp.expType = c1.dataType;
+                  else if(c2.dataType.kind == floatType)    exp.expType = c2.dataType;
+                  else
+                     exp.expType = c1.dataType;
+               }
+               else if((c1 && c1.type == unitClass) || exp.op.op == '/')   // 1/units should not be typed with unit
+                  exp.expType = type1;
+               else
+                  exp.expType = type2;
+
+               if(exp.expType)
+                  exp.expType.refCount++;
+            }
             else if(exp.op.exp1 && exp.op.exp2 &&
                ((useSideType /*&&
                      (useSideUnit ||
-                        ((!type1 || type1.kind != classType || type1._class.registered.type != unitClass) &&
-                         (!type2 || type2.kind != classType || type2._class.registered.type != unitClass)))*/) ||
+                        ((!c1 || c1.type != unitClass) &&
+                         (!c2 || c2.type != unitClass)))*/) ||
                   ((!type1 || type1.kind != classType || !strcmp(type1._class.string, "String")) &&
                   (!type2 || type2.kind != classType || !strcmp(type2._class.string, "String")))))
             {
@@ -8588,18 +8873,9 @@ void ProcessExpressionType(Expression exp)
                   ((type1.kind == classType && type1._class && strcmp(type1._class.string, "String")) == (type2.kind == classType && type2._class && strcmp(type2._class.string, "String"))))
                {
                   // Added this check for enum subtraction to result in an int type:
-                  if(exp.op.op == '-' &&
-                     ((type1.kind == classType && type1._class.registered && type1._class.registered.type == enumClass) ||
-                      (type2.kind == classType && type2._class.registered && type2._class.registered.type == enumClass)) )
+                  if(exp.op.op == '-' && ((c1 && c1.type == enumClass) || (c2 && c2.type == enumClass)) )
                   {
-                     Type intType;
-                     if(!type1._class.registered.dataType)
-                        type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
-                     if(!type2._class.registered.dataType)
-                        type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
-
-                     intType = ProcessTypeString(
-                        (type1._class.registered.dataType.kind == int64Type || type2._class.registered.dataType.kind == int64Type) ? "int64" : "int", false);
+                     Type intType = ProcessTypeString((c1 && c1.dataType.kind == int64Type) || (c2 && c2.dataType.kind == int64Type) ? "int64" : "int", false);
 
                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
@@ -8618,12 +8894,17 @@ void ProcessExpressionType(Expression exp)
                   }
 
                   // Warning here for adding Radians + Degrees with no destination type
-                  if(!boolResult && type1.kind == classType && (!exp.destType || exp.destType.kind != classType) &&
-                     type1._class.registered && type1._class.registered.type == unitClass &&
-                     type2._class.registered && type2._class.registered.type == unitClass &&
-                     type1._class.registered != type2._class.registered)
-                     Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
-                        type1._class.string, type2._class.string, type1._class.string);
+                  if(!boolResult && !exp.opDestType && (!exp.destType || exp.destType.kind != classType) &&
+                     c1 && c1.type == unitClass &&
+                     c2 && c2.type == unitClass &&
+                     c1 != c2)
+                  {
+                     if(exp.usedInComparison || exp.parentOpDestType)
+                        exp.ambiguousUnits = true;
+                     else
+                        Compiler_Warning($"operating on %s and %s with an untyped result, assuming %s\n",
+                           type1._class.string, type2._class.string, type1._class.string);
+                  }
 
                   if(type1.kind == pointerType && type1.type.kind == templateType && type2.kind != pointerType)
                   {
@@ -8648,7 +8929,7 @@ void ProcessExpressionType(Expression exp)
                            {
                               if(type2)
                                  FreeType(type2);
-                              type2 = exp.op.exp2.expType = ProcessTypeString("int", false);
+                              type2 = exp.op.exp2.expType = ProcessTypeString("int", false); c2 = null;
                               type2.refCount++;
                            }
 
@@ -8781,7 +9062,7 @@ void ProcessExpressionType(Expression exp)
                   }
                }
                // ADDED THESE TWO FROM OUTSIDE useSideType CHECK
-               else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type2 && type1 && type2.kind == classType && type1.kind != classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
+               else if(!boolResult && !useSideUnit && c2 && c2.type == unitClass && type1 && type1.kind != classType)
                {
                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
                   // Convert e.g. / 4 into / 4.0
@@ -8792,7 +9073,7 @@ void ProcessExpressionType(Expression exp)
                   exp.expType = type2;
                   if(type2) type2.refCount++;
                }
-               else if(!boolResult && (!useSideUnit /*|| exp.destType*/) && type1 && type2 && type1.kind == classType && type2.kind != classType && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
+               else if(!boolResult && !useSideUnit && c1 && c1.type == unitClass && type2 && type2.kind != classType)
                {
                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
                   // Convert e.g. / 4 into / 4.0
@@ -8807,36 +9088,34 @@ void ProcessExpressionType(Expression exp)
                {
                   bool valid = false;
 
-                  if(!boolResult && useSideUnit && type1 && type1.kind == classType && type1._class.registered && type1._class.registered.type == unitClass && type2 && type2.kind != classType)
+                  if(!boolResult && useSideUnit && c1 && c1.type == unitClass && type2 && type2.kind != classType)
                   {
                      if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
 
-                     if(!type1._class.registered.dataType)
-                        type1._class.registered.dataType = ProcessTypeString(type1._class.registered.dataTypeString, false);
-                     exp.op.exp2.destType = type1._class.registered.dataType;
+                     exp.op.exp2.destType = c1.dataType;
                      exp.op.exp2.destType.refCount++;
 
                      CheckExpressionType(exp.op.exp2, exp.op.exp2.destType, false, false);
                      if(type2)
                         FreeType(type2);
                      type2 = exp.op.exp2.destType;
+                     c2 = type2 && type2.kind == classType && type2._class ? type2._class.registered : null;
                      if(type2) type2.refCount++;
 
                      exp.expType = type2;
                      type2.refCount++;
                   }
 
-                  if(!boolResult && useSideUnit && type2 && type2.kind == classType && type2._class.registered && type2._class.registered.type == unitClass && type1 && type1.kind != classType)
+                  if(!boolResult && useSideUnit && c2 && c2.type == unitClass && type1 && type1.kind != classType)
                   {
                      if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
 
-                     if(!type2._class.registered.dataType)
-                        type2._class.registered.dataType = ProcessTypeString(type2._class.registered.dataTypeString, false);
-                     exp.op.exp1.destType = type2._class.registered.dataType;
+                     exp.op.exp1.destType = c2.dataType;
                      exp.op.exp1.destType.refCount++;
 
                      CheckExpressionType(exp.op.exp1, exp.op.exp1.destType, false, false);
                      type1 = exp.op.exp1.destType;
+                     c1 = type1 && type1.kind == classType && type1._class ? type1._class.registered : null;
                      exp.expType = type1;
                      type1.refCount++;
                   }
@@ -8844,8 +9123,8 @@ void ProcessExpressionType(Expression exp)
                   // TESTING THIS NEW CODE
                   if(!boolResult || exp.op.op == '>' || exp.op.op == '<' || exp.op.op == GE_OP || exp.op.op == LE_OP)
                   {
-                     bool op1IsEnum = type1 && type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass;
-                     bool op2IsEnum = type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass;
+                     bool op1IsEnum = c1 && c1.type == enumClass;
+                     bool op2IsEnum = c2 && c2.type == enumClass;
                      if(exp.op.op == '*' || exp.op.op == '/' || exp.op.op == '-' || exp.op.op == '|' || exp.op.op == '^')
                      {
                         // Convert the enum to an int instead for these operators
@@ -8898,8 +9177,7 @@ void ProcessExpressionType(Expression exp)
                   if(!valid)
                   {
                      // Added this first part of the if here to handle  5 + Degrees { 5 } with either a base unit dest or not a unit dest type
-                     if(type2 && type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == unitClass &&
-                        (type1.kind != classType || !type1._class || !type1._class.registered || type1._class.registered.type != unitClass))
+                     if(c2 && c2.type == unitClass && (!c1 || c1.type != unitClass))
                      {
                         if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
                         exp.op.exp1.destType = type2;
@@ -8986,12 +9264,12 @@ void ProcessExpressionType(Expression exp)
 
                            Compiler_Warning($"incompatible expressions %s (%s) and %s (%s)\n", expString1, type1String, expString2, type2String);
 
-                           if(type1.kind == classType && type1._class && type1._class.registered && type1._class.registered.type == enumClass)
+                           if(c1 && c1.type == enumClass)
                            {
                               exp.expType = exp.op.exp1.expType;
                               if(exp.op.exp1.expType) exp.op.exp1.expType.refCount++;
                            }
-                           else if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
+                           else if(c2 && c2.type == enumClass)
                            {
                               exp.expType = exp.op.exp2.expType;
                               if(exp.op.exp2.expType) exp.op.exp2.expType.refCount++;
@@ -9003,7 +9281,7 @@ void ProcessExpressionType(Expression exp)
                else if(type2)
                {
                   // Maybe this was meant to be an enum...
-                  if(type2.kind == classType && type2._class && type2._class.registered && type2._class.registered.type == enumClass)
+                  if(c2 && c2.type == enumClass)
                   {
                      Type oldType = exp.op.exp1.expType;
                      exp.op.exp1.expType = null;
@@ -9046,7 +9324,7 @@ void ProcessExpressionType(Expression exp)
             }
             else if(type2 && (!type1 || (type2.kind == classType && type1.kind != classType)))
             {
-               if(type1 && type2._class && type2._class.registered && type2._class.registered.type == unitClass)
+               if(type1 && c2 && c2.type == unitClass)
                {
                   if(exp.op.exp1.destType) FreeType(exp.op.exp1.destType);
                   // Convert e.g. / 4 into / 4.0
@@ -9068,7 +9346,7 @@ void ProcessExpressionType(Expression exp)
             }
             else if(type1 && (!type2 || (type1.kind == classType && type2.kind != classType)))
             {
-               if(type2 && type1._class && type1._class.registered && type1._class.registered.type == unitClass)
+               if(c2 && c2.type == unitClass)
                {
                   if(exp.op.exp2.destType) FreeType(exp.op.exp2.destType);
                   // Convert e.g. / 4 into / 4.0
@@ -9146,16 +9424,21 @@ void ProcessExpressionType(Expression exp)
             {
                FreeType(e.destType);
                e.opDestType = exp.opDestType;
+               e.usedInComparison = exp.usedInComparison;
+               e.parentOpDestType = exp.parentOpDestType;
                e.destType = exp.destType;
                if(e.destType) { exp.destType.refCount++; /*e.destType.count++; inced = true;*/ }
             }
             ProcessExpressionType(e);
+            if(e.ambiguousUnits)
+               exp.ambiguousUnits = true;
             /*if(inced)
                exp.destType.count--;*/
             if(!exp.expType && !e.next)
             {
                exp.expType = e.expType;
                if(e.expType) e.expType.refCount++;
+               exp.needCast = e.needCast;
             }
             if(!e.isConstant)
                exp.isConstant = false;
@@ -10222,6 +10505,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 +10604,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 +11375,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 +11460,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 && !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 +11789,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 +11802,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 +11815,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 +11937,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 +11958,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 +11970,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 +11998,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 +12074,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 +12117,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 +12221,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 +12752,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 +12801,7 @@ static void ProcessStatement(Statement stmt)
       }
       case badDeclarationStmt:
       {
-         ProcessDeclaration(stmt.decl);
+         ProcessDeclaration(stmt.decl, true);
          break;
       }
       case asmStmt:
@@ -12474,15 +12873,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);
 
@@ -12907,7 +13306,7 @@ static void ProcessFunction(FunctionDefinition function)
             if(_class.fixed)
             {
                Expression e;
-               if(_class.offset && _class.offset == _class.base.structSize)
+               if(_class.offset && _class.offset == (_class.base.type == noHeadClass ? _class.base.memberOffset : _class.base.structSize))
                {
                   e = MkExpClassSize(MkSpecifierName(_class.base.fullName));
                   ProcessExpressionType(e);
@@ -13063,7 +13462,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 +13581,8 @@ void DeclareFunctionUtil(External neededBy, const String s)
       FindSymbol(s, globalContext, globalContext, false, false);
 }
 
+bool reachedPass15;
+
 void ComputeDataTypes()
 {
    External external;
@@ -13211,6 +13612,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 +13639,7 @@ void ComputeDataTypes()
 
          currentClass = null;
          if(external.declaration)
-            ProcessDeclaration(external.declaration);
+            ProcessDeclaration(external.declaration, true);
       }
       else if(external.type == classExternal)
       {