compiler: (WIP) Fixes for MinGW/GCC 5
[sdk] / compiler / libec / src / pass15.ec
index 2c584d9..cc4aaef 100644 (file)
@@ -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;
          }
@@ -1628,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++;
@@ -2215,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)
@@ -2971,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))
                {
@@ -3186,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))
@@ -3584,7 +3595,7 @@ 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);
@@ -3755,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);
@@ -4389,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)
@@ -5722,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);
@@ -6517,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)
 {
    /*
@@ -6559,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();
@@ -6569,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")))));
@@ -6576,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);
@@ -6632,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)
@@ -6858,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:
@@ -6910,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;
@@ -7765,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;
@@ -7830,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*/)
             {
@@ -7856,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)
@@ -8249,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
@@ -8295,6 +8425,7 @@ void ProcessExpressionType(Expression exp)
                // Gives boolean result
                boolResult = true;
                useSideType = true;
+               relationOp = true;
                break;
             case '+':
             case '-':
@@ -8319,6 +8450,7 @@ void ProcessExpressionType(Expression exp)
             case '%':
                useSideType = true;
                useDestType = true;
+               if(exp.op.op == '/') powerOp = true;
                break;
             case '&':
             case '*':
@@ -8327,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;
 
@@ -8384,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...
@@ -8392,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 &&
@@ -8495,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)
@@ -8523,8 +8672,16 @@ 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 == '~'))
@@ -8598,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;
 
@@ -8629,6 +8804,11 @@ void ProcessExpressionType(Expression exp)
          }
          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)
@@ -8658,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")))))
             {
@@ -8671,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);
@@ -8701,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)
                   {
@@ -8731,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++;
                            }
 
@@ -8864,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
@@ -8875,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
@@ -8890,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++;
                   }
@@ -8927,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
@@ -8981,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;
@@ -9069,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++;
@@ -9086,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;
@@ -9129,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
@@ -9151,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
@@ -9229,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;