home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / smc / BIND.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  264.8 KB  |  9,546 lines

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. #include "comp.h"
  7. #include "genIL.h"
  8.  
  9. /*****************************************************************************/
  10.  
  11. #ifdef  DEBUG
  12.  
  13. #if     0
  14. #define SHOW_CODE_OF_THIS_FNC   "name"          // will display code for this fn
  15. #endif
  16.  
  17. #if     0
  18. #define SHOW_OVRS_OF_THIS_FNC   "f"             // disp overload res for this fn
  19. #endif
  20.  
  21. #undef  SHOW_OVRS_OF_CONVS                      // disp overload res for conversions
  22.  
  23. #endif
  24.  
  25. /*****************************************************************************
  26.  *
  27.  *  The low-level tree node allocator to be used during expression binding.
  28.  */
  29.  
  30. Tree                compiler::cmpAllocExprRaw(Tree expr, treeOps oper)
  31. {
  32.     if  (!expr)
  33.     {
  34. #if MGDDATA
  35.         expr = new Tree;
  36. #else
  37.         expr =    (Tree)cmpAllocCGen.nraAlloc(sizeof(*expr));
  38. #endif
  39.  
  40. //      expr->tnColumn = 0;
  41.         expr->tnLineNo = 0;
  42.     }
  43.  
  44.     expr->tnOper  = oper;
  45.     expr->tnFlags = 0;
  46.  
  47.     return  expr;
  48. }
  49.  
  50. /*****************************************************************************
  51.  *
  52.  *  Return an error node.
  53.  */
  54.  
  55. Tree                compiler::cmpCreateErrNode(unsigned errn)
  56. {
  57.     Tree            expr = cmpAllocExprRaw(NULL, TN_ERROR);
  58.  
  59.     if  (errn)
  60.         cmpError(errn);
  61.  
  62.     expr->tnVtyp = TYP_UNDEF;
  63.     expr->tnType = cmpGlobalST->stIntrinsicType(TYP_UNDEF);
  64.  
  65.     return  expr;
  66. }
  67.  
  68. /*****************************************************************************
  69.  *
  70.  *  Given a type, check whether it's un unmanaged array and if so decay its
  71.  *  type to a pointer to the array element.
  72.  */
  73.  
  74. Tree                compiler::cmpDecayArray(Tree expr)
  75. {
  76.     TypDef          type = expr->tnType;
  77.  
  78.     if  (type->tdTypeKind == TYP_ARRAY && !type->tdIsManaged)
  79.     {
  80.         var_types       vtyp = TYP_PTR;
  81.  
  82.         /* Check for a managed address, it yields a byref */
  83.  
  84.         if  (cmpIsManagedAddr(expr))
  85.             vtyp = TYP_REF;
  86.  
  87.         /* Create the implicit 'address of' node */
  88.  
  89.         expr = cmpCreateExprNode(NULL,
  90.                                  TN_ADDROF,
  91.                                  cmpGlobalST->stNewRefType(vtyp, type->tdArr.tdaElem),
  92.                                  expr,
  93.                                  NULL);
  94.  
  95.         expr->tnFlags |= TNF_ADR_IMPLICIT;
  96.     }
  97.  
  98.     return  expr;
  99. }
  100.  
  101. /*****************************************************************************
  102.  *
  103.  *  Return a node that refers to the given local variable symbol.
  104.  */
  105.  
  106. Tree                compiler::cmpCreateVarNode(Tree expr, SymDef sym)
  107. {
  108.     expr = cmpAllocExprRaw(expr, TN_LCL_SYM);
  109.  
  110.     expr->tnLclSym.tnLclSym = sym; sym->sdReferenced = true;
  111.  
  112.     if  (sym->sdCompileState >= CS_DECLARED)
  113.     {
  114.         /* Is the variable a byref argument? */
  115.  
  116.         if  (sym->sdVar.sdvMgdByRef || sym->sdVar.sdvUmgByRef)
  117.         {
  118.             assert(sym->sdVar.sdvArgument);
  119.  
  120.             /* Bash the type of the argument reference to ref/pointer */
  121.  
  122.             expr->tnVtyp   = sym->sdVar.sdvMgdByRef ? TYP_REF : TYP_PTR;
  123.             expr->tnType   = cmpGlobalST->stNewRefType(expr->tnVtypGet(), sym->sdType);
  124.             expr->tnFlags &= ~TNF_LVALUE;
  125.  
  126.             /* Create an explicit indirection */
  127.  
  128.             expr = cmpCreateExprNode(NULL, TN_IND, sym->sdType, expr, NULL);
  129.         }
  130.         else
  131.         {
  132.             expr->tnType   = sym->sdType;
  133.             expr->tnVtyp   = expr->tnType->tdTypeKind;
  134.  
  135.             /* Is the variable a constant? */
  136.  
  137.             if  (sym->sdVar.sdvConst)
  138.                 return  cmpFetchConstVal(sym->sdVar.sdvCnsVal, expr);
  139.         }
  140.     }
  141.     else
  142.     {
  143.         cmpError(ERRlvInvisible, sym);
  144.  
  145.         expr->tnVtyp       = TYP_UNDEF;
  146.         expr->tnType       = cmpGlobalST->stIntrinsicType(TYP_UNDEF);
  147.     }
  148.  
  149.     expr->tnFlags |=  TNF_LVALUE;
  150.  
  151. AGAIN:
  152.  
  153.     switch (expr->tnVtyp)
  154.     {
  155.     case TYP_TYPEDEF:
  156.         expr->tnType = cmpActualType(expr->tnType);
  157.         expr->tnVtyp = expr->tnType->tdTypeKindGet();
  158.         goto AGAIN;
  159.  
  160.     case TYP_ARRAY:
  161.         expr = cmpDecayCheck(expr);
  162.         break;
  163.     }
  164.  
  165.     return expr;
  166. }
  167.  
  168. /*****************************************************************************
  169.  *
  170.  *  Return a 32-bit integer constant node.
  171.  */
  172.  
  173. Tree                compiler::cmpCreateIconNode(Tree expr, __int32 val, var_types typ)
  174. {
  175.     expr = cmpAllocExprRaw(expr, TN_CNS_INT);
  176.  
  177.     assert(typ != TYP_LONG && typ != TYP_ULONG);
  178.  
  179.     expr->tnVtyp             = typ;
  180.     expr->tnType             = cmpGlobalST->stIntrinsicType(typ);
  181.     expr->tnIntCon.tnIconVal = val;
  182.  
  183.     return expr;
  184. }
  185.  
  186. /*****************************************************************************
  187.  *
  188.  *  Return a 64-bit integer constant node.
  189.  */
  190.  
  191. Tree                compiler::cmpCreateLconNode(Tree expr, __int64 val, var_types typ)
  192. {
  193.     expr = cmpAllocExprRaw(expr, TN_CNS_LNG);
  194.  
  195.     assert(typ == TYP_LONG || typ == TYP_ULONG);
  196.  
  197.     expr->tnVtyp             = typ;
  198.     expr->tnType             = cmpGlobalST->stIntrinsicType(typ);
  199.     expr->tnLngCon.tnLconVal = val;
  200.  
  201.     return expr;
  202. }
  203.  
  204. /*****************************************************************************
  205.  *
  206.  *  Return a float constant node.
  207.  */
  208.  
  209. Tree                compiler::cmpCreateFconNode(Tree expr, float val)
  210. {
  211.     expr = cmpAllocExprRaw(expr, TN_CNS_FLT);
  212.  
  213.     expr->tnVtyp             = TYP_FLOAT;
  214.     expr->tnType             = cmpGlobalST->stIntrinsicType(TYP_FLOAT);
  215.     expr->tnFltCon.tnFconVal = val;
  216.  
  217.     return expr;
  218. }
  219.  
  220. /*****************************************************************************
  221.  *
  222.  *  Return a float constant node.
  223.  */
  224.  
  225. Tree                compiler::cmpCreateDconNode(Tree expr, double val)
  226. {
  227.     expr = cmpAllocExprRaw(expr, TN_CNS_DBL);
  228.  
  229.     expr->tnVtyp             = TYP_DOUBLE;
  230.     expr->tnType             = cmpGlobalST->stIntrinsicType(TYP_DOUBLE);
  231.     expr->tnDblCon.tnDconVal = val;
  232.  
  233.     return expr;
  234. }
  235. /*****************************************************************************
  236.  *
  237.  *  Return a string constant node.
  238.  */
  239.  
  240. Tree                compiler::cmpCreateSconNode(stringBuff  str,
  241.                                                 size_t      len,
  242.                                                 unsigned    wide,
  243.                                                 TypDef      type)
  244. {
  245.     Tree            expr;
  246.  
  247.     expr = cmpAllocExprRaw(NULL, TN_CNS_STR);
  248.  
  249.     expr->tnType             = type;
  250.     expr->tnVtyp             = type->tdTypeKindGet();
  251.     expr->tnStrCon.tnSconVal = str;
  252.     expr->tnStrCon.tnSconLen = len;
  253.     expr->tnStrCon.tnSconLCH = wide;
  254.  
  255.     return expr;
  256. }
  257.  
  258. /*****************************************************************************
  259.  *
  260.  *  Allocate a generic expression tree node with the given type.
  261.  */
  262.  
  263. Tree                compiler::cmpCreateExprNode(Tree expr, treeOps  oper,
  264.                                                            TypDef   type)
  265. {
  266.     expr = cmpAllocExprRaw(expr, oper);
  267.  
  268.     expr->tnFlags    = 0;
  269.     expr->tnVtyp     = type->tdTypeKind;
  270.     expr->tnType     = type;
  271.  
  272.     if  (expr->tnVtyp == TYP_TYPEDEF)
  273.     {
  274.         expr->tnType = type = type->tdTypedef.tdtType;
  275.         expr->tnVtyp = type->tdTypeKindGet();
  276.     }
  277.  
  278. //  if  ((int)expr == 0x00a5033c) forceDebugBreak();
  279.  
  280.     return  expr;
  281. }
  282.  
  283. Tree                compiler::cmpCreateExprNode(Tree expr, treeOps  oper,
  284.                                                            TypDef   type,
  285.                                                            Tree     op1,
  286.                                                            Tree     op2)
  287. {
  288.     expr = cmpAllocExprRaw(expr, oper);
  289.  
  290.     expr->tnFlags    = 0;
  291.     expr->tnVtyp     = type->tdTypeKind;
  292.     expr->tnType     = type;
  293.     expr->tnOp.tnOp1 = op1;
  294.     expr->tnOp.tnOp2 = op2;
  295.  
  296.     if  (expr->tnVtyp == TYP_TYPEDEF)
  297.     {
  298.         expr->tnType = type = type->tdTypedef.tdtType;
  299.         expr->tnVtyp = type->tdTypeKindGet();
  300.     }
  301.  
  302. //  if  ((int)expr == 0x00a5033c) forceDebugBreak();
  303.  
  304.     return  expr;
  305. }
  306.  
  307. /*****************************************************************************
  308.  *
  309.  *  Bring the two given class/array expressions to a common type if possible.
  310.  *  Returns non-zero in case of success (in which either of the expressions
  311.  *  may have been coerced to the proper type).
  312.  */
  313.  
  314. bool                compiler::cmpConvergeValues(INOUT Tree REF op1,
  315.                                                 INOUT Tree REF op2)
  316. {
  317.     TypDef          bt1 = op1->tnType;
  318.     TypDef          bt2 = op2->tnType;
  319.  
  320.     assert(bt1->tdTypeKind == TYP_REF ||
  321.            bt1->tdTypeKind == TYP_PTR ||
  322.            bt1->tdTypeKind == TYP_ARRAY);
  323.  
  324.     assert(bt2->tdTypeKind == TYP_REF ||
  325.            bt2->tdTypeKind == TYP_PTR ||
  326.            bt2->tdTypeKind == TYP_ARRAY);
  327.  
  328.     /* Are both operands the same? */
  329.  
  330.     if  (bt1 == bt2)
  331.         return true;
  332.  
  333.     /* Special case: 'null' always 'bends' to the other type */
  334.  
  335.     if  (op1->tnOper == TN_NULL)
  336.     {
  337.         op1 = cmpCoerceExpr(op1, op2->tnType, false);
  338.         return true;
  339.     }
  340.  
  341.     if  (op2->tnOper == TN_NULL)
  342.     {
  343.         op2 = cmpCoerceExpr(op2, op1->tnType, false);
  344.         return true;
  345.     }
  346.  
  347.     /* Arrays require special handling */
  348.  
  349.     if  (bt1->tdTypeKind == TYP_ARRAY)
  350.     {
  351.         if  (cmpIsObjectVal(op2))
  352.         {
  353.             /* 'Object' is a base class of all arrays */
  354.  
  355.             op1 = cmpCoerceExpr(op1, op2->tnType, false);
  356.             return true;
  357.         }
  358.  
  359.         /* Is the other operand another array? */
  360.  
  361.         if  (bt2->tdTypeKind != TYP_ARRAY)
  362.             return false;
  363.  
  364.         /* Get hold of the element types */
  365.  
  366.         bt1 = cmpDirectType(bt1->tdArr.tdaElem);
  367.         bt2 = cmpDirectType(bt2->tdArr.tdaElem);
  368.  
  369.         if  (bt1 == bt2)
  370.             return  true;
  371.  
  372.         /* Is one element type the base of the other? */
  373.  
  374.         if  (bt1->tdTypeKind != TYP_REF) return false;
  375.         if  (bt2->tdTypeKind != TYP_REF) return false;
  376.  
  377.         goto CHK_BASE;
  378.     }
  379.  
  380.     if  (bt2->tdTypeKind == TYP_ARRAY)
  381.     {
  382.         if  (cmpIsObjectVal(op1))
  383.         {
  384.             /* 'Object' is a base class of all arrays */
  385.  
  386.             op2 = cmpCoerceExpr(op2, op1->tnType, false);
  387.             return true;
  388.         }
  389.  
  390.         /* We already know that the other operand is not an array */
  391.  
  392.         return false;
  393.     }
  394.  
  395. CHK_BASE:
  396.  
  397.     /* Is one operand a base class of the other? */
  398.  
  399.     bt1 = cmpGetRefBase(bt1);
  400.     bt2 = cmpGetRefBase(bt2);
  401.  
  402.     if  (!bt1 || bt1->tdTypeKind != TYP_CLASS) return true;
  403.     if  (!bt2 || bt2->tdTypeKind != TYP_CLASS) return true;
  404.  
  405.     if      (cmpIsBaseClass(bt1, bt2))
  406.     {
  407.         op2 = cmpCoerceExpr(op2, op1->tnType, false);
  408.         return true;
  409.     }
  410.     else if (cmpIsBaseClass(bt2, bt1))
  411.     {
  412.         op1 = cmpCoerceExpr(op1, op2->tnType, false);
  413.         return true;
  414.     }
  415.  
  416.     return false;
  417. }
  418.  
  419. /*****************************************************************************
  420.  *
  421.  *  Make sure access to the specified symbol is permitted right now; issues
  422.  *  an error message and returns false if access it not allowed.
  423.  */
  424.  
  425. bool                compiler::cmpCheckAccessNP(SymDef sym)
  426. {
  427.     SymDef          clsSym;
  428.     SymDef          nspSym;
  429.  
  430.     /* Figure out the class/namespace owning the symbol */
  431.  
  432.     clsSym = sym->sdParent;
  433.     if  (!clsSym)
  434.         return  true;
  435.  
  436.     if  (clsSym->sdSymKind != SYM_CLASS)
  437.     {
  438.         nspSym = clsSym;
  439.         clsSym = NULL;
  440.     }
  441.     else
  442.     {
  443.         nspSym = clsSym->sdParent;
  444.         while (nspSym->sdSymKind != SYM_NAMESPACE)
  445.             nspSym = nspSym->sdParent;
  446.     }
  447.  
  448.     /* Check the access level of the symbol */
  449.  
  450.     switch (sym->sdAccessLevel)
  451.     {
  452.     case ACL_PUBLIC:
  453.         return true;
  454.  
  455.     case ACL_DEFAULT:
  456.  
  457.         /* Is this a type that came from an external assembly ? */
  458.  
  459.         if  (sym->sdSymKind == SYM_CLASS && sym->sdClass.sdcAssemIndx)
  460.             break;
  461.  
  462.         /* Are we within the same namespace? */
  463.  
  464.         if  (cmpCurNS == nspSym)
  465.             return true;
  466.  
  467.         /* If the symbol is not an import, it's OK as well */
  468.  
  469.         if  (!sym->sdIsImport)
  470.             return true;
  471.  
  472.         // Fall through ...
  473.  
  474.     case ACL_PROTECTED:
  475.  
  476.         /* Are we in a member of a derived class? */
  477.  
  478.         if  (cmpCurCls && clsSym)
  479.         {
  480.             SymDef          nestCls;
  481.  
  482.             for (nestCls = cmpCurCls;
  483.                  nestCls && nestCls->sdSymKind == SYM_CLASS;
  484.                  nestCls = nestCls->sdParent)
  485.             {
  486.                 if  (cmpIsBaseClass(clsSym->sdType, nestCls->sdType))
  487.                     return true;
  488.             }
  489.         }
  490.  
  491.         // Fall through ...
  492.  
  493.     case ACL_PRIVATE:
  494.  
  495.         /* Are we within a member of the same class? */
  496.  
  497.         if  (cmpCurCls == clsSym)
  498.             return true;
  499.  
  500.         /* Are we nested within the same class? */
  501.  
  502.         if  (cmpCurCls)
  503.         {
  504.             SymDef          tmpSym = cmpCurCls;
  505.  
  506.             do
  507.             {
  508.                  tmpSym = tmpSym->sdParent;
  509.                  if (tmpSym == clsSym)
  510.                      return true;
  511.             }
  512.             while (tmpSym->sdSymKind == SYM_CLASS);
  513.         }
  514.  
  515.         break;
  516.  
  517.     default:
  518. #ifdef  DEBUG
  519.         printf("Symbol '%s'\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  520. #endif
  521.         assert(!"invalid symbol access");
  522.     }
  523.  
  524.     /*
  525.         Last-ditch effort: always allow access to interface members
  526.         as well as property symbols (for those we check access on
  527.         the accessor instead).
  528.      */
  529.  
  530.     if  (clsSym && clsSym->sdClass.sdcFlavor == STF_INTF)
  531.         return  true;
  532.     if  (sym->sdSymKind == SYM_PROP)
  533.         return  true;
  534.  
  535. //  #pragma message("WARNING: access checking disabled near line 1280!")
  536. //  return  true;
  537.  
  538.     forceDebugBreak();
  539.     cmpErrorQnm(ERRnoAccess, sym);
  540.     return false;
  541. }
  542.  
  543. /*****************************************************************************
  544.  *
  545.  *  The given type is an "indirect" one (i.e. a typedef or enum), convert
  546.  *  it to the underlying type.
  547.  */
  548.  
  549. TypDef              compiler::cmpGetActualTP(TypDef type)
  550. {
  551.     for (;;)
  552.     {
  553.         switch (type->tdTypeKind)
  554.         {
  555.         case TYP_TYPEDEF:
  556.             type = type->tdTypedef.tdtType;
  557.             if  (varTypeIsIndirect(type->tdTypeKindGet()))
  558.                 continue;
  559.             break;
  560.  
  561.         case TYP_ENUM:
  562.             type = type->tdEnum.tdeIntType;
  563.             break;
  564.         }
  565.  
  566.         return  type;
  567.     }
  568. }
  569.  
  570. /*****************************************************************************
  571.  *
  572.  *  Make sure the given expression is an lvalue.
  573.  */
  574.  
  575. bool                compiler::cmpCheckLvalue(Tree expr, bool addr, bool noErr)
  576. {
  577.     if  (expr->tnFlags & TNF_LVALUE)
  578.     {
  579.         /* If we're taking the address of this thing ... */
  580.  
  581.         if  (addr)
  582.         {
  583.             /* ... then it better not be a bitfield */
  584.  
  585.             if  (expr->tnOper == TN_VAR_SYM)
  586.             {
  587.                 SymDef          memSym = expr->tnVarSym.tnVarSym;
  588.  
  589.                 assert(memSym->sdSymKind == SYM_VAR);
  590.  
  591.                 if  (memSym->sdVar.sdvBitfield)
  592.                 {
  593.                     if  (noErr)
  594.                         return  false;
  595.  
  596.                     cmpError(ERRbfldAddr, memSym);
  597.                 }
  598.             }
  599.         }
  600.     }
  601.     else
  602.     {
  603.         /* Try to give a more specific message */
  604.  
  605.         switch (expr->tnOper)
  606.         {
  607.             SymDef          sym;
  608.  
  609.         case TN_VAR_SYM:
  610.  
  611.             sym = expr->tnVarSym.tnVarSym;
  612.             goto CHK_CNS;
  613.  
  614.         case TN_LCL_SYM:
  615.  
  616.             sym = expr->tnLclSym.tnLclSym;
  617.  
  618.         CHK_CNS:
  619.  
  620.             if  (sym->sdVar.sdvConst || sym->sdIsSealed)
  621.             {
  622.                 /* Special case: readonly members can be assigned in ctors */
  623.  
  624.                 if  (cmpCurFncSym && cmpCurFncSym->sdFnc.sdfCtor
  625.                                   && cmpCurFncSym->sdParent == sym->sdParent)
  626.                 {
  627.                     /* Allow assignments to the member */
  628.  
  629.                     expr->tnFlags |= TNF_LVALUE;
  630.  
  631.                     return  true;
  632.                 }
  633.  
  634.                 if  (!noErr)
  635.                     cmpError(ERRassgCns, expr->tnVarSym.tnVarSym);
  636.  
  637.                 return false;
  638.             }
  639.  
  640.             break;
  641.         }
  642.  
  643.         if  (!noErr)
  644.         {
  645.             cmpRecErrorPos(expr);
  646.  
  647.             cmpError((expr->tnOperKind() & TNK_CONST) ? ERRassgLit
  648.                                                       : ERRnotLvalue);
  649.         }
  650.  
  651.         return false;
  652.     }
  653.  
  654.     return true;
  655. }
  656.  
  657. /*****************************************************************************
  658.  *
  659.  *  See if the value of the given condition expression can be determined
  660.  *  trivially at compile time. The return value is as follows:
  661.  *
  662.  *      -1      The condition is always 'false'
  663.  *       0      The condition value cannot be determined at compile time
  664.  *      +1      The condition is always 'true'
  665.  */
  666.  
  667. int                 compiler::cmpEvalCondition(Tree cond)
  668. {
  669.     if  (cond->tnOper == TN_CNS_INT)
  670.     {
  671.         if  (cond->tnIntCon.tnIconVal)
  672.             return +1;
  673.         else
  674.             return -1;
  675.     }
  676.  
  677.     // CONSIDER: Add more tests (like a string literal is always non-zero)
  678.  
  679.     return 0;
  680. }
  681.  
  682. /*****************************************************************************
  683.  *
  684.  *  Return an expression that yields the value of "this" (the caller has
  685.  *  already checked that we're in a non-static member function).
  686.  */
  687.  
  688. inline
  689. Tree                compiler::cmpThisRefOK()
  690. {
  691.     Tree            args;
  692.  
  693.     assert(cmpThisSym);
  694.  
  695.     args = cmpCreateVarNode(NULL, cmpThisSym);
  696.     args->tnFlags &= ~TNF_LVALUE;
  697.  
  698.     return args;
  699. }
  700.  
  701. /*****************************************************************************
  702.  *
  703.  *  Return an expression that yields the value of "this". If we're not in
  704.  *  a non-static member function, an error is issued and NULL is returned.
  705.  */
  706.  
  707. Tree                compiler::cmpThisRef()
  708. {
  709.     if  (cmpThisSym)
  710.     {
  711.         return  cmpThisRefOK();
  712.     }
  713.     else
  714.     {
  715.         return  cmpCreateErrNode(ERRbadThis);
  716.     }
  717. }
  718.  
  719. /*****************************************************************************
  720.  *
  721.  *  Given an expression that refers to a member of the current class,
  722.  *  prefix it with an implicit "this." reference.
  723.  */
  724.  
  725. Tree                compiler::cmpBindThisRef(SymDef sym)
  726. {
  727.     /* Make sure we have a 'this' pointer */
  728.  
  729.     if  (cmpThisSym)
  730.     {
  731.         Tree            expr;
  732.  
  733.         /* Create a variable member reference off of 'this' */
  734.  
  735.         expr = cmpCreateExprNode(NULL, TN_VAR_SYM, sym->sdType);
  736.  
  737.         expr->tnVarSym.tnVarObj = cmpThisRef();
  738.         expr->tnVarSym.tnVarSym = sym;
  739.  
  740.         if  (!sym->sdVar.sdvConst && !sym->sdIsSealed)
  741.             expr->tnFlags |= TNF_LVALUE;
  742.  
  743.         return expr;
  744.     }
  745.  
  746.     cmpErrorQnm(ERRmemWOthis, sym);
  747.     return cmpCreateErrNode();
  748. }
  749.  
  750. /*****************************************************************************
  751.  *
  752.  *  We've got an expression that references an anonymous union member. Return
  753.  *  a fully qualified access expression that will select the proper member.
  754.  */
  755.  
  756. Tree                compiler::cmpRefAnUnionMem(Tree expr)
  757. {
  758.     SymDef          sym;
  759.     SymDef          uns;
  760.     Tree            obj;
  761.  
  762.     assert(expr->tnOper == TN_VAR_SYM);
  763.  
  764.     sym = expr->tnVarSym.tnVarSym; assert(sym->sdSymKind == SYM_VAR);
  765.     uns = sym->sdParent;           assert(symTab::stIsAnonUnion(uns));
  766.     obj = expr->tnVarSym.tnVarObj; assert(obj);
  767.  
  768.     do
  769.     {
  770.         Tree            temp;
  771.         SymXinfoSym     tmem = cmpFindSymInfo(uns->sdClass.sdcExtraInfo, XI_UNION_MEM);
  772.  
  773.         assert(tmem);
  774.  
  775.         /* Insert an explicit member selector */
  776.  
  777.         temp = cmpCreateExprNode(NULL, TN_VAR_SYM, uns->sdType);
  778.  
  779.         temp->tnVarSym.tnVarObj = obj;
  780.         temp->tnVarSym.tnVarSym = tmem->xiSymInfo;
  781.  
  782.         obj = temp;
  783.         sym = uns;
  784.         uns = uns->sdParent;
  785.     }
  786.     while (symTab::stIsAnonUnion(uns));
  787.  
  788.     expr->tnVarSym.tnVarObj = obj;
  789.  
  790.     return  expr;
  791. }
  792.  
  793. /*****************************************************************************
  794.  *
  795.  *  Create a reference to a data member of a class or a global variable.
  796.  */
  797.  
  798. Tree                compiler::cmpRefMemberVar(Tree expr, SymDef sym, Tree objx)
  799. {
  800.     assert(sym);
  801.     assert(sym->sdSymKind == SYM_VAR || sym->sdSymKind == SYM_PROP);
  802.  
  803.     /* Make sure we are allowed to access the variable */
  804.  
  805.     cmpCheckAccess(sym);
  806.  
  807.     /* Has the member been marked as "deprecated" ? */
  808.  
  809.     if  (sym->sdIsImport && (sym->sdIsDeprecated || (sym->sdIsMember && sym->sdParent->sdIsDeprecated)))
  810.     {
  811.         if  (sym->sdIsDeprecated)
  812.         {
  813.             if  (sym->sdSymKind == SYM_VAR)
  814.                 cmpObsoleteUse(sym, WRNdepFld);
  815.             else
  816.                 cmpObsoleteUse(sym, WRNdepProp);
  817.         }
  818.         else
  819.         {
  820.             cmpObsoleteUse(sym->sdParent, WRNdepCls);
  821.         }
  822.     }
  823.  
  824.     /* Prefix with 'this' if this is a non-static member */
  825.  
  826.     if  (sym->sdIsStatic || !sym->sdIsMember)
  827.     {
  828.         /* Static member -- make sure this is not a forward reference */
  829.  
  830.         if  (sym->sdCompileState < CS_CNSEVALD)
  831.         {
  832.             if  (sym->sdSymKind == SYM_VAR)
  833.             {
  834.                 if  (sym->sdVar.sdvInEval ||
  835.                      sym->sdVar.sdvDeferCns)
  836.                 {
  837.                     cmpEvalCnsSym(sym, true);
  838.                 }
  839.                 else
  840.                     cmpDeclSym(sym);
  841.             }
  842.             else
  843.                 cmpDeclSym(sym);
  844.  
  845.             sym->sdCompileState = CS_CNSEVALD;
  846.         }
  847.  
  848.         /* Create a data member reference */
  849.  
  850.         expr->tnOper            = TN_VAR_SYM;
  851.         expr->tnType            = sym->sdType;
  852.         expr->tnVtyp            = sym->sdType->tdTypeKind;
  853.  
  854.         expr->tnVarSym.tnVarSym = sym;
  855.         expr->tnVarSym.tnVarObj = objx;
  856.  
  857.         /* Is this a variable or a property? */
  858.  
  859.         if  (sym->sdSymKind == SYM_VAR)
  860.         {
  861.             /* Is the variable a constant? */
  862.  
  863. //          if  (sym->sdName && !strcmp(sym          ->sdSpelling(), "MinValue")
  864. //                           && !strcmp(sym->sdParent->sdSpelling(), "SByte")) forceDebugBreak();
  865.  
  866.             if  (sym->sdVar.sdvConst)
  867.             {
  868.                 expr = cmpFetchConstVal(sym->sdVar.sdvCnsVal, expr);
  869.             }
  870.             else
  871.             {
  872.                 if (!sym->sdIsSealed)
  873.                     expr->tnFlags |= TNF_LVALUE;
  874.             }
  875.         }
  876.         else
  877.         {
  878.             expr->tnOper   = TN_PROPERTY;
  879.             expr->tnFlags |= TNF_LVALUE;
  880.         }
  881.     }
  882.     else
  883.     {
  884.         SymDef          cls;
  885.  
  886.         /* Non-static member -- we'll need an object address */
  887.  
  888.         if  (objx)
  889.         {
  890.             /* Create a data member reference */
  891.  
  892.             expr->tnOper            = TN_VAR_SYM;
  893.             expr->tnType            = sym->sdType;
  894.             expr->tnVtyp            = sym->sdType->tdTypeKind;
  895.  
  896.             expr->tnVarSym.tnVarSym = sym;
  897.             expr->tnVarSym.tnVarObj = objx;
  898.  
  899.             if  (!sym->sdIsSealed)
  900.                 expr->tnFlags |= TNF_LVALUE;
  901.         }
  902.         else
  903.         {
  904.             /* Caller didn't supply an object address, use "this" implicitly */
  905.  
  906.             if  (cmpCurCls == NULL)
  907.             {
  908.             NO_THIS:
  909.                 cmpErrorQnm(ERRmemWOthis, sym);
  910.                 return cmpCreateErrNode();
  911.             }
  912.  
  913.             cls = cmpSymbolOwner(sym); assert(cls && cls->sdSymKind == SYM_CLASS);
  914.  
  915.             if  (!cmpIsBaseClass(cls->sdType, cmpCurCls->sdType))
  916.                 goto NO_THIS;
  917.  
  918.             expr = cmpBindThisRef(sym);
  919.             if  (expr->tnOper == TN_ERROR)
  920.                 return  expr;
  921.  
  922.             assert(expr->tnOper == TN_VAR_SYM);
  923.             objx = expr->tnVarSym.tnVarObj;
  924.         }
  925.  
  926.         /* Is this a "normal" member or property? */
  927.  
  928.         if  (sym->sdSymKind == SYM_VAR)
  929.         {
  930.             /* Is this a bitfield member? */
  931.  
  932.             if  (sym->sdVar.sdvBitfield)
  933.             {
  934.                 assert(sym->sdIsStatic == false);
  935.                 assert(objx);
  936.  
  937.                 /* Change the node to a bitfield */
  938.  
  939.                 expr->tnOper            = TN_BFM_SYM;
  940.  
  941.                 expr->tnBitFld.tnBFinst = objx;
  942.                 expr->tnBitFld.tnBFmsym = sym;
  943.                 expr->tnBitFld.tnBFoffs = sym->sdVar.sdvOffset;
  944.                 expr->tnBitFld.tnBFlen  = sym->sdVar.sdvBfldInfo.bfWidth;
  945.                 expr->tnBitFld.tnBFpos  = sym->sdVar.sdvBfldInfo.bfOffset;
  946.             }
  947.         }
  948.         else
  949.         {
  950.             expr->tnOper = TN_PROPERTY;
  951.         }
  952.     }
  953.  
  954.     /* Special case: member of anonymous union */
  955.  
  956.     if  (sym->sdSymKind == SYM_VAR && sym->sdVar.sdvAnonUnion)
  957.     {
  958.         assert(expr->tnVarSym.tnVarSym == sym);
  959.         assert(expr->tnVarSym.tnVarObj != NULL);
  960.  
  961.         expr = cmpRefAnUnionMem(expr);
  962.     }
  963.  
  964.     return  cmpDecayCheck(expr);
  965. }
  966.  
  967. /*****************************************************************************
  968.  *
  969.  *  Bind a reference to a simple name.
  970.  */
  971.  
  972. Tree                compiler::cmpBindName(Tree expr, bool isCall,
  973.                                                      bool classOK)
  974. {
  975.     SymTab          ourStab = cmpGlobalST;
  976.  
  977.     Ident           name;
  978.     name_space      nsp;
  979.     SymDef          scp;
  980.     SymDef          sym;
  981.  
  982.     /* Is the operand a qualified symbol name? */
  983.  
  984.     if  (expr->tnOper == TN_ANY_SYM)
  985.     {
  986.         sym = expr->tnSym.tnSym;
  987.         scp = expr->tnSym.tnScp;
  988.         goto CHKSYM;
  989.     }
  990.  
  991.     assert(expr->tnOper == TN_NAME);
  992.  
  993.     /* Lookup the name in the current context */
  994.  
  995.     name = expr->tnName.tnNameId;
  996.  
  997.     /* Figure out what namespace to look in */
  998.  
  999.     nsp  = NS_NORM;
  1000.     if  (classOK)
  1001.         nsp = (name_space)(NS_TYPE|NS_NORM);
  1002.     if  (expr->tnFlags & TNF_NAME_TYPENS)
  1003.         nsp = NS_TYPE;
  1004.  
  1005.     scp = NULL;
  1006.     sym = ourStab->stLookupSym(name, nsp);
  1007.  
  1008.     if  (!sym)
  1009.     {
  1010.         /* Special case: "va_start" and "va_arg" */
  1011.  
  1012.         if  (name == cmpIdentVAbeg && isCall)
  1013.         {
  1014.             sym = cmpFNsymVAbeg;
  1015.             if  (!sym)
  1016.             {
  1017.                 sym = cmpFNsymVAbeg = ourStab->stDeclareSym(name, SYM_FNC, NS_HIDE, NULL);
  1018.                 sym->sdType = cmpTypeVoidFnc;
  1019.             }
  1020.  
  1021.             goto CHKSYM;
  1022.         }
  1023.  
  1024.         if  (name == cmpIdentVAget && isCall)
  1025.         {
  1026.             sym = cmpFNsymVAget;
  1027.             if  (!sym)
  1028.             {
  1029.                 sym = cmpFNsymVAget = ourStab->stDeclareSym(name, SYM_FNC, NS_HIDE, NULL);
  1030.                 sym->sdType = cmpTypeVoidFnc;
  1031.             }
  1032.  
  1033.             goto CHKSYM;
  1034.         }
  1035.  
  1036.         /* Declare a symbol in the current function to prevent repeated errors */
  1037.  
  1038.         sym = ourStab->stDeclareLcl(name,
  1039.                                     SYM_ERR,
  1040.                                     NS_NORM,
  1041.                                     cmpCurScp,
  1042.                                     &cmpAllocCGen);
  1043.  
  1044.         sym->sdType         = ourStab->stIntrinsicType(TYP_UNDEF);
  1045.         sym->sdCompileState = CS_DECLARED;
  1046.  
  1047.         cmpRecErrorPos(expr);
  1048.         cmpError(ERRundefName, expr->tnName.tnNameId);
  1049.         return cmpCreateErrNode();
  1050.     }
  1051.  
  1052. CHKSYM:
  1053.  
  1054.     /* Make sure the name looks kosher */
  1055.  
  1056.     switch (sym->sdSymKind)
  1057.     {
  1058.         TypDef          type;
  1059.         TypDef          base;
  1060.  
  1061.     case SYM_VAR:
  1062.     case SYM_PROP:
  1063.  
  1064.         /* Make sure a variable is acceptable here */
  1065.  
  1066.         if  (isCall)
  1067.         {
  1068.             /* No good - we need a function here */
  1069.  
  1070.             switch (sym->sdType->tdTypeKind)
  1071.             {
  1072.             case TYP_UNDEF:
  1073.                 break;
  1074.  
  1075.             case TYP_PTR:
  1076.  
  1077.                 /* Pointer to function is acceptable for calls */
  1078.  
  1079.                 base = cmpActualType(sym->sdType->tdRef.tdrBase);
  1080.                 if  (base->tdTypeKind == TYP_FNC)
  1081.                     goto MEM_REF;
  1082.  
  1083.                 // Fall through ...
  1084.  
  1085.             default:
  1086.                 cmpError(ERRnotAfunc, sym);
  1087.             }
  1088.  
  1089.             return cmpCreateErrNode();
  1090.         }
  1091.  
  1092.     MEM_REF:
  1093.  
  1094.         /* In case something goes wrong ... */
  1095.  
  1096.         cmpRecErrorPos(expr);
  1097.  
  1098.         /* Is this a local variable or a class member? */
  1099.  
  1100.         if  (sym->sdIsMember || !sym->sdVar.sdvLocal)
  1101.             expr = cmpRefMemberVar (expr, sym);
  1102.         else
  1103.             expr = cmpCreateVarNode(expr, sym);
  1104.  
  1105.         /* Indirect through the result if we have a fn ptr call */
  1106.  
  1107.         if  (isCall)
  1108.         {
  1109.             assert(sym->sdType->tdTypeKind == TYP_PTR);
  1110.             assert(base->tdTypeKind == TYP_FNC);
  1111.  
  1112.             expr = cmpCreateExprNode(NULL, TN_IND, base, expr, NULL);
  1113.         }
  1114.  
  1115.         break;
  1116.  
  1117.     case SYM_FNC:
  1118.  
  1119.         assert((int)scp != 0xDDDDDDDD);
  1120.  
  1121.         /* If we've found a function, it must be a global or a member of our class */
  1122.  
  1123.         expr = cmpCreateExprNode(expr, TN_FNC_SYM, sym->sdType);
  1124.         expr->tnFncSym.tnFncSym  = sym;
  1125.         expr->tnFncSym.tnFncArgs = NULL;
  1126.         expr->tnFncSym.tnFncObj  = NULL;
  1127.         expr->tnFncSym.tnFncScp  = scp;
  1128.  
  1129.         if  (sym->sdIsMember && !sym->sdIsStatic && cmpThisSym && cmpCurCls != sym->sdParent)
  1130.         {
  1131.             SymDef          fncClsSym = sym->sdParent;
  1132.  
  1133.             assert(cmpCurCls && cmpCurCls->sdSymKind == SYM_CLASS && cmpCurCls == cmpCurFncSym->sdParent);
  1134.             assert(fncClsSym && fncClsSym->sdSymKind == SYM_CLASS);
  1135.  
  1136.             /* Is the function a member of our class or its base? */
  1137.  
  1138.             if  (cmpIsBaseClass(cmpCurCls->sdType, fncClsSym->sdType))
  1139.                 expr->tnFncSym.tnFncObj = cmpThisRefOK();
  1140.         }
  1141.  
  1142.         /* Make sure a function member is acceptable here */
  1143.  
  1144.         if  (!isCall)
  1145.         {
  1146.             /* Presumably we're passing a function pointer */
  1147.  
  1148.             if  (sym->sdIsMember && !sym->sdIsStatic)
  1149.             {
  1150.                 expr->tnOper = TN_FNC_PTR;
  1151.             }
  1152.             else
  1153.             {
  1154.                 expr = cmpCreateExprNode(NULL,
  1155.                                          TN_ADDROF,
  1156.                                          cmpGlobalST->stNewRefType(TYP_PTR, expr->tnType),
  1157.                                          expr,
  1158.                                          NULL);
  1159.             }
  1160.         }
  1161.  
  1162.         break;
  1163.  
  1164.     case SYM_ENUM:
  1165.     case SYM_CLASS:
  1166.  
  1167.         /* If a class/enum name isn't acceptable here, report that and bail */
  1168.  
  1169.         if  (!classOK)
  1170.         {
  1171.         BAD_USE:
  1172.  
  1173.             cmpRecErrorPos(expr);
  1174.             cmpErrorQnm(ERRbadNameUse, sym);
  1175.  
  1176.             return cmpCreateErrNode();
  1177.         }
  1178.  
  1179.         /* Make sure the class/enum type is fully defined before proceeding */
  1180.  
  1181.         cmpDeclSym(sym);
  1182.  
  1183.         expr->tnOper     = TN_CLASS;
  1184.         expr->tnType     = sym->sdType;
  1185.         expr->tnVtyp     = sym->sdType->tdTypeKind;
  1186.  
  1187.         expr->tnOp.tnOp1 =
  1188.         expr->tnOp.tnOp2 = NULL;
  1189.  
  1190.         return expr;
  1191.  
  1192.     case SYM_NAMESPACE:
  1193.  
  1194.         /* If a class/namespace name isn't acceptable here, pretend it's undefined */
  1195.  
  1196.         if  (!classOK)
  1197.             goto BAD_USE;
  1198.  
  1199.         expr->tnOper            = TN_NAMESPACE;
  1200.         expr->tnType            = cmpTypeVoid;
  1201.         expr->tnVtyp            = TYP_VOID;
  1202.         expr->tnLclSym.tnLclSym = sym;
  1203.  
  1204.         return expr;
  1205.  
  1206.     case SYM_ENUMVAL:
  1207.  
  1208.         type = sym->sdType;
  1209.         assert(type->tdTypeKind == TYP_ENUM);
  1210.  
  1211.         /* Has the enum value been marked as "deprecated" ? */
  1212.  
  1213.         if  (sym->sdIsImport && (sym->sdIsDeprecated || (sym->sdIsMember && sym->sdParent->sdIsDeprecated)))
  1214.         {
  1215.             if  (sym->sdIsDeprecated)
  1216.                 cmpObsoleteUse(sym, WRNdepEnum);
  1217.             else
  1218.                 cmpObsoleteUse(sym->sdParent, WRNdepCls);
  1219.         }
  1220.  
  1221.         /* Make sure we have the enum member's value */
  1222.  
  1223.         if  (!sym->sdIsDefined)
  1224.         {
  1225.             if  (sym->sdCompileState == CS_DECLSOON)
  1226.             {
  1227.                 cmpError(ERRcircDep, sym);
  1228.                 sym->sdCompileState = CS_DECLARED;
  1229.             }
  1230.             else
  1231.                 cmpDeclEnum(type->tdEnum.tdeSymbol);
  1232.         }
  1233.  
  1234.         /* Fetch the value of the enum */
  1235.  
  1236.         if  (type->tdEnum.tdeIntType->tdTypeKind >= TYP_LONG)
  1237.             expr = cmpCreateLconNode(expr, *sym->sdEnumVal.sdEV.sdevLval, TYP_LONG);
  1238.         else
  1239.             expr = cmpCreateIconNode(expr,  sym->sdEnumVal.sdEV.sdevIval, TYP_INT);
  1240.  
  1241.         expr->tnType = sym->sdType;
  1242.         expr->tnVtyp = TYP_ENUM;
  1243.         break;
  1244.  
  1245.     case SYM_ERR:
  1246.         return cmpCreateErrNode();
  1247.  
  1248.     default:
  1249.         assert(!"unexpected symbol kind");
  1250.     }
  1251.  
  1252.     return expr;
  1253. }
  1254.  
  1255. /*****************************************************************************
  1256.  *
  1257.  *  Bind a dotted or arrowed name reference. Such a name may mean a number
  1258.  *  of things, for example:
  1259.  *
  1260.  *      instance->data_member
  1261.  *      instance->func_member(args)
  1262.  *      classname.membername
  1263.  *
  1264.  *  etc...
  1265.  */
  1266.  
  1267. Tree                compiler::cmpBindDotArr(Tree expr, bool isCall, bool classOK)
  1268. {
  1269.     Tree            opTree;
  1270.     Tree            nmTree;
  1271.     Tree            objPtr;
  1272.     TypDef          clsTyp;
  1273.     SymDef          clsSym;
  1274.     Ident           memNam;
  1275.     SymDef          memSym;
  1276.     Tree            args;
  1277.     name_space      nsp;
  1278.  
  1279.     unsigned        flags  = expr->tnFlags;
  1280.     TypDef          boxCls = NULL;
  1281.  
  1282.     assert(expr->tnOper == TN_DOT  ||
  1283.            expr->tnOper == TN_ARROW);
  1284.  
  1285.     /*
  1286.         We have to check for the special strange case of multiple dots,
  1287.         since in that case the parse tree will have the wrong order for
  1288.         binding the dots (which needs to be done left to right).
  1289.      */
  1290.  
  1291.     opTree = expr->tnOp.tnOp1;
  1292.     nmTree = expr->tnOp.tnOp2;
  1293.     assert(nmTree->tnOper == TN_NAME);
  1294.     memNam = nmTree->tnName.tnNameId;
  1295.  
  1296. //  static int x; if (++x == 0) forceDebugBreak();
  1297.  
  1298.     /* Figure out what namespace to look in */
  1299.  
  1300.     nsp  = classOK ? (name_space)(NS_TYPE|NS_NORM)
  1301.                    : NS_NORM;
  1302.  
  1303.     /* See if the left operand is a name or another dot */
  1304.  
  1305.     switch (opTree->tnOper)
  1306.     {
  1307.     case TN_DOT:
  1308.     case TN_ARROW:
  1309.         objPtr = cmpBindDotArr (opTree, false, true);
  1310.         break;
  1311.  
  1312.     case TN_NAME:
  1313.     case TN_ANY_SYM:
  1314.         objPtr = cmpBindNameUse(opTree, false, true);
  1315.         break;
  1316.  
  1317.     default:
  1318.         objPtr = cmpBindExprRec(opTree);
  1319.         break;
  1320.     }
  1321.  
  1322.     if  (objPtr->tnVtyp == TYP_UNDEF)
  1323.         return objPtr;
  1324.  
  1325.     /* Check for some special cases */
  1326.  
  1327.     switch (objPtr->tnOper)
  1328.     {
  1329.         SymDef          nspSym;
  1330.  
  1331.     case TN_CLASS:
  1332.  
  1333.         if  (expr->tnOper == TN_ARROW)
  1334.             cmpError(ERRbadArrowNC);
  1335.  
  1336.         clsTyp = objPtr->tnType;
  1337.         objPtr = NULL;
  1338.  
  1339.         if  (clsTyp->tdTypeKind == TYP_ENUM)
  1340.         {
  1341.             SymDef          enumSym = clsTyp->tdEnum.tdeSymbol;
  1342.  
  1343.             assert(enumSym && enumSym->sdSymKind == SYM_ENUM);
  1344.  
  1345.             if  (enumSym->sdCompileState < CS_DECLARED)
  1346.                 cmpDeclEnum(enumSym, true);
  1347.  
  1348.             memSym = cmpGlobalST->stLookupScpSym(memNam, enumSym);
  1349.  
  1350.             if  (!memSym)
  1351.             {
  1352.                 cmpError(ERRnotMember, enumSym, memNam);
  1353.                 return cmpCreateErrNode();
  1354.             }
  1355.  
  1356.             expr->tnOper      = TN_ANY_SYM;
  1357.             expr->tnSym.tnSym = memSym;
  1358.             expr->tnSym.tnScp = NULL;
  1359.  
  1360.             return  cmpBindName(expr, false, false);
  1361.         }
  1362.         break;
  1363.  
  1364.     case TN_NAMESPACE:
  1365.  
  1366.         if  (expr->tnOper == TN_ARROW)
  1367.             cmpError(ERRbadArrowNC);
  1368.  
  1369.         /* We have "namespace.name" */
  1370.  
  1371.         nspSym = objPtr->tnLclSym.tnLclSym;
  1372.  
  1373.         assert(nspSym);
  1374.         assert(nspSym->sdSymKind == SYM_NAMESPACE);
  1375.  
  1376.         /* Is it OK to have a class/package name here? */
  1377.  
  1378.         if  (!classOK)
  1379.         {
  1380.             cmpErrorQnm(ERRbadNameUse, nspSym);
  1381.             return cmpCreateErrNode();
  1382.         }
  1383.  
  1384.         /* Look for a matching nested namespace or class */
  1385.  
  1386.         memSym = cmpGlobalST->stLookupNspSym(memNam, NS_NORM, nspSym);
  1387.         if  (!memSym)
  1388.         {
  1389.             cmpError(ERRundefNspm, nspSym, memNam);
  1390.             return cmpCreateErrNode();
  1391.         }
  1392.  
  1393.         /* Set the node to class/namespace as appropriate */
  1394.  
  1395.         switch (memSym->sdSymKind)
  1396.         {
  1397.         case SYM_NAMESPACE:
  1398.             objPtr->tnLclSym.tnLclSym = memSym;
  1399.             break;
  1400.  
  1401.         case SYM_ENUM:
  1402.         case SYM_CLASS:
  1403.  
  1404.         CLS_REF:
  1405.  
  1406.             objPtr = cmpCreateExprNode(objPtr, TN_CLASS, memSym->sdType, NULL, NULL);
  1407.             break;
  1408.  
  1409.         default:
  1410.             assert(!"unexpected namespace member found");
  1411.         }
  1412.  
  1413.         return objPtr;
  1414.  
  1415.     default:
  1416.  
  1417.         /* The first operand must be a class */
  1418.  
  1419.         clsTyp = objPtr->tnType;
  1420.  
  1421.         if  (clsTyp->tdTypeKind != TYP_REF &&
  1422.              clsTyp->tdTypeKind != TYP_PTR)
  1423.         {
  1424.             /* OK, we'll take "array.length" as well */
  1425.  
  1426.             if  (clsTyp->tdTypeKind != TYP_ARRAY)
  1427.             {
  1428.                 TypDef          type;
  1429.  
  1430.                 /* Remember the type we started with */
  1431.  
  1432.                 boxCls = clsTyp;
  1433.  
  1434.                 /* If this is a dot, we'll also allow structs */
  1435.  
  1436.                 if  (expr->tnOper == TN_DOT && clsTyp->tdTypeKind == TYP_CLASS)
  1437.                 {
  1438.                     var_types       ptrVtp;
  1439.                     TypDef          ptrTyp;
  1440.  
  1441.                     /* Does the class have a matching member? */
  1442.  
  1443.                     if  (!cmpGlobalST->stLookupClsSym(memNam, clsTyp->tdClass.tdcSymbol))
  1444.                     {
  1445.                         Tree            objx;
  1446.  
  1447.                         /* Is there an implicit conversion to object? */
  1448.  
  1449.                         objx = cmpCheckConvOper(objPtr, NULL, cmpObjectRef(), false);
  1450.                         if  (objx)
  1451.                         {
  1452.                             boxCls = NULL;
  1453.                             objPtr = objx;
  1454.                             clsTyp = cmpClassObject->sdType;
  1455.                             break;
  1456.                         }
  1457.                     }
  1458.  
  1459.                     /* Take the address of the operand and use "->" on it */
  1460.  
  1461.                     ptrVtp = clsTyp->tdIsManaged ? TYP_REF : TYP_PTR;
  1462.                     ptrTyp = cmpGlobalST->stNewRefType(ptrVtp, clsTyp);
  1463.  
  1464.                     /* The address of "*ptr" is "ptr", of course */
  1465.  
  1466.                     if  (objPtr->tnOper == TN_IND)
  1467.                     {
  1468.                         objPtr         = objPtr->tnOp.tnOp1;
  1469.                         objPtr->tnType = ptrTyp;
  1470.                         objPtr->tnVtyp = ptrVtp;
  1471.                     }
  1472.                     else
  1473.                     {
  1474.                         objPtr = cmpCreateExprNode(NULL,
  1475.                                                    TN_ADDROF,
  1476.                                                    ptrTyp,
  1477.                                                    objPtr,
  1478.                                                    NULL);
  1479.                     }
  1480.  
  1481.                     break;
  1482.                 }
  1483.  
  1484.                 type = cmpCheck4valType(clsTyp);
  1485.  
  1486.                 /* Is this a struct equivalent of an intrinsic type? */
  1487.  
  1488.                 if  (type)
  1489.                 {
  1490.                     objPtr = cmpCoerceExpr(objPtr, type, false);
  1491.                     objPtr = cmpCreateExprNode(NULL,
  1492.                                                TN_ADDROF,
  1493.                                                type->tdClass.tdcRefTyp,
  1494.                                                objPtr,
  1495.                                                NULL);
  1496.                     clsTyp =
  1497.                     boxCls = type;
  1498.                 }
  1499.                 else
  1500.                 {
  1501.                     objPtr = cmpCoerceExpr(objPtr, cmpRefTpObject, false);
  1502.                     clsTyp = cmpClassObject->sdType;
  1503.                 }
  1504.                 break;
  1505.  
  1506.             DOT_ERR:
  1507.  
  1508.                 cmpError((expr->tnOper == TN_DOT) ? ERRbadDotOp
  1509.                                                   : ERRbadArrOp, clsTyp);
  1510.                 return cmpCreateErrNode();
  1511.             }
  1512.  
  1513.             /* We have an array value followed by "." */
  1514.  
  1515.             assert(objPtr->tnVtyp == TYP_ARRAY);
  1516.  
  1517.             /* Simply treat the value as having the type 'System.Array' */
  1518.  
  1519.             clsSym         = cmpClassArray;
  1520.  
  1521.             objPtr->tnType = cmpArrayRef();
  1522.             objPtr->tnVtyp = TYP_REF;
  1523.  
  1524.             memSym = cmpGlobalST->stLookupAllCls(memNam, clsSym, NS_NORM, CS_DECLARED);
  1525.             if  (memSym)
  1526.                 goto FOUND_MEM;
  1527.  
  1528.             cmpError(ERRnotMember, clsTyp, memNam);
  1529.             return cmpCreateErrNode();
  1530.         }
  1531.  
  1532.         clsTyp = clsTyp->tdRef.tdrBase;
  1533.  
  1534.         if  (clsTyp->tdTypeKind != TYP_CLASS)
  1535.             goto DOT_ERR;
  1536.  
  1537.         break;
  1538.     }
  1539.  
  1540.     /* Lookup the name (the second operand) in the class */
  1541.  
  1542.     assert(clsTyp->tdTypeKind == TYP_CLASS);
  1543.     clsSym = clsTyp->tdClass.tdcSymbol;
  1544.  
  1545.     memSym = cmpGlobalST->stLookupAllCls(memNam, clsSym, nsp, CS_DECLARED);
  1546.  
  1547.     if  (!memSym)
  1548.     {
  1549.  
  1550.         cmpError(ERRnotMember, clsSym, memNam);
  1551.         return cmpCreateErrNode();
  1552.     }
  1553.  
  1554. FOUND_MEM:
  1555.  
  1556.     /* Is it a data or function member (or a property) ? */
  1557.  
  1558.     switch (memSym->sdSymKind)
  1559.     {
  1560.     case SYM_FNC:
  1561.  
  1562.         args = cmpCreateExprNode(NULL, isCall ? TN_FNC_SYM
  1563.                                               : TN_FNC_PTR, memSym->sdType);
  1564.  
  1565.         args->tnFncSym.tnFncObj  = objPtr;
  1566.         args->tnFncSym.tnFncSym  = memSym;
  1567.         args->tnFncSym.tnFncArgs = NULL;
  1568.         args->tnFncSym.tnFncScp  = clsSym;
  1569.  
  1570.         if  (boxCls && memSym->sdParent->sdType != boxCls && objPtr->tnOper != TN_BOX
  1571.                                                           && objPtr->tnOper != TN_ERROR)
  1572.         {
  1573.             if  (objPtr->tnOper == TN_ADDROF)
  1574.             {
  1575.                 objPtr = objPtr->tnOp.tnOp1;
  1576.             }
  1577.             else
  1578.             {
  1579.                 assert(objPtr->tnOper == TN_UNBOX);
  1580.             }
  1581.  
  1582.             assert(clsTyp->tdTypeKind == TYP_CLASS);
  1583.  
  1584.             args->tnFncSym.tnFncObj = cmpCreateExprNode(NULL,
  1585.                                                         TN_BOX,
  1586.                                                         clsTyp->tdClass.tdcRefTyp,
  1587.                                                         objPtr);
  1588.         }
  1589.         break;
  1590.  
  1591.     case SYM_VAR:
  1592.     case SYM_PROP:
  1593.  
  1594.         if  (isCall)
  1595.         {
  1596.             cmpError(ERRbadArgs, memSym);
  1597.             return cmpCreateErrNode();
  1598.         }
  1599.  
  1600.         /* In case something goes wrong ... */
  1601.  
  1602.         cmpRecErrorPos(nmTree);
  1603.  
  1604.         /* Make sure we can access the member this way */
  1605.  
  1606.         args = cmpRefMemberVar(nmTree, memSym, objPtr);
  1607.  
  1608.         /* Is this a property reference? */
  1609.  
  1610.         if  (args->tnOper == TN_PROPERTY)
  1611.         {
  1612.             if  (!(flags & TNF_ASG_DEST))
  1613.                 args = cmpBindProperty(args, NULL, NULL);
  1614.         }
  1615.  
  1616.         break;
  1617.  
  1618.     case SYM_CLASS:
  1619.         goto CLS_REF;
  1620.  
  1621.     default:
  1622.         UNIMPL(!"unexpected symbol kind");
  1623.     }
  1624.  
  1625.     return args;
  1626. }
  1627.  
  1628. /*****************************************************************************/
  1629. /*****************************************************************************
  1630.  *
  1631.  *  Returns non-zero if the given expression (or expression list) contains
  1632.  *  a TYP_UNDEF entry.
  1633.  */
  1634.  
  1635. bool                compiler::cmpExprIsErr(Tree expr)
  1636. {
  1637.     while   (expr)
  1638.     {
  1639.         if  (expr->tnVtyp == TYP_UNDEF)
  1640.             return true;
  1641.  
  1642.         if  (expr->tnOper != TN_LIST)
  1643.             break;
  1644.  
  1645.         if  (expr->tnOp.tnOp1->tnVtyp == TYP_UNDEF)
  1646.             return true;
  1647.  
  1648.         expr = expr->tnOp.tnOp2;
  1649.     }
  1650.  
  1651.     return false;
  1652. }
  1653.  
  1654. /*****************************************************************************
  1655.  *
  1656.  *  Given an integer or floating-point constant, figure out the smallest
  1657.  *  type the value fits in.
  1658.  */
  1659.  
  1660. var_types           compiler::cmpConstSize(Tree expr, var_types vtp)
  1661. {
  1662.     if  (expr->tnFlags & TNF_BEEN_CAST)
  1663.         return  vtp;
  1664.  
  1665.     if  (expr->tnOper == TN_CNS_INT)
  1666.     {
  1667.         if  (vtp > TYP_NATINT)
  1668.             return vtp;
  1669.  
  1670.         __int32     value = expr->tnIntCon.tnIconVal;
  1671.  
  1672.         if  (value < 128   && value >= -128)
  1673.             return TYP_CHAR;
  1674.  
  1675.         if  (value < 256   && value >= 0)
  1676.             return TYP_UCHAR;
  1677.  
  1678.         if  (value < 32768 && value >= -32768)
  1679.             return TYP_SHORT;
  1680.  
  1681.         if  (value < 65536 && value >= 0)
  1682.             return TYP_SHORT;
  1683.     }
  1684.  
  1685.     return  vtp;
  1686. }
  1687.  
  1688. /*****************************************************************************
  1689.  *
  1690.  *  Given a value of type Object, unbox it to the specified type.
  1691.  */
  1692.  
  1693. Tree                compiler::cmpUnboxExpr(Tree expr, TypDef type)
  1694. {
  1695.     TypDef          ptrt;
  1696.  
  1697.     /* Special case: "Object -> struct" may be a conversion */
  1698.  
  1699.     if  (type->tdTypeKind == TYP_CLASS)
  1700.     {
  1701.         Tree            conv;
  1702.  
  1703.         /* Look for an appropriate overloaded conversion operator */
  1704.  
  1705.         conv = cmpCheckConvOper(expr, NULL, type, true);
  1706.         if  (conv)
  1707.             return  conv;
  1708.     }
  1709.  
  1710.     ptrt = cmpGlobalST->stNewRefType(TYP_PTR, type);
  1711.  
  1712.     expr = cmpCreateExprNode(NULL, TN_UNBOX, ptrt, expr);
  1713.     expr = cmpCreateExprNode(NULL, TN_IND  , type, expr);
  1714.  
  1715.     // ISSUE: Is the result of unboxing an lvalue or not?
  1716.  
  1717.     return  expr;
  1718. }
  1719.  
  1720. /*****************************************************************************
  1721.  *
  1722.  *  Make sure we didn't mess up a cast (in terms of context flavors).
  1723.  */
  1724.  
  1725. #ifndef NDEBUG
  1726.  
  1727. void                compiler::cmpChk4ctxChange(TypDef type1,
  1728.                                                TypDef type2, unsigned flags)
  1729. {
  1730.     if  (type1->tdTypeKind == TYP_REF &&
  1731.          type2->tdTypeKind == TYP_REF)
  1732.     {
  1733.         TypDef          base1 = cmpGetRefBase(type1);
  1734.         TypDef          base2 = cmpGetRefBase(type2);
  1735.  
  1736.         if  (base1 && base1->tdTypeKind == TYP_CLASS &&
  1737.              base2 && base2->tdTypeKind == TYP_CLASS)
  1738.         {
  1739.             if  (cmpDiffContext(base1, base2))
  1740.             {
  1741.                 if  ((flags & TNF_CTX_CAST) != 0)
  1742.                     return;
  1743.  
  1744.                 printf("Type 1 = '%s'\n", cmpGlobalST->stTypeName(type1, NULL, NULL, NULL, false));
  1745.                 printf("Type 2 = '%s'\n", cmpGlobalST->stTypeName(type2, NULL, NULL, NULL, false));
  1746.  
  1747.                 UNIMPL(!"context change slipped through!");
  1748.             }
  1749.         }
  1750.     }
  1751.  
  1752.     if  ((flags & TNF_CTX_CAST) == 0)
  1753.         return;
  1754.  
  1755.     printf("Type 1 = '%s'\n", cmpGlobalST->stTypeName(type1, NULL, NULL, NULL, false));
  1756.     printf("Type 2 = '%s'\n", cmpGlobalST->stTypeName(type2, NULL, NULL, NULL, false));
  1757.  
  1758.     UNIMPL(!"bogus context change marked in cast node!");
  1759. }
  1760.  
  1761. #endif
  1762.  
  1763. /*****************************************************************************
  1764.  *
  1765.  *  The following table yields the conversion cost for arithmetic conversions.
  1766.  */
  1767.  
  1768. const   unsigned    convCostTypeMin = TYP_BOOL;
  1769. const   unsigned    convCostTypeMax = TYP_LONGDBL;
  1770.  
  1771. static  signed char arithCost[][convCostTypeMax - convCostTypeMin + 1] =
  1772. {
  1773. // from       to BOOL   WCHAR  CHAR   UCHAR  SHORT  USHRT  INT    UINT   N-INT  LONG   ULONG  FLOAT  DBL    LDBL
  1774. /* BOOL    */  {   0  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  },
  1775. /* WCHAR   */  {  20  ,   0  ,  20  ,  20  ,  20  ,   1  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  ,   7  ,   8  },
  1776. /* CHAR    */  {  20  ,   1  ,   0  ,  20  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  ,   7  ,   8  ,   9  ,  10  },
  1777. /* UCHAR   */  {  20  ,   1  ,  20  ,   0  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  ,   7  ,   8  ,   9  ,  10  },
  1778. /* SHORT   */  {  20  ,  20  ,  20  ,  20  ,   2  ,  20  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  ,   7  ,   8  },
  1779. /* USHORT  */  {  20  ,   1  ,  20  ,  20  ,  20  ,   0  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  ,   7  ,   8  },
  1780. /* INT     */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,  20  ,   1  ,   2  ,   3  ,   4  ,   5  ,   6  },
  1781. /* UINT    */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,  20  ,   1  ,   2  ,   3  ,   4  ,   5  },
  1782. /* NATINT  */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,   1  ,  20  ,  20  ,  20  ,  20  },
  1783. /* LONG    */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,  20  ,  20  ,  20  ,  20  },
  1784. /* ULONG   */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,  20  ,  20  ,  20  },
  1785. /* FLOAT   */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,   1  ,   2  },
  1786. /* DOUBLE  */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  ,   1  },
  1787. /* LONGDBL */  {  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,  20  ,   0  },
  1788. };
  1789.  
  1790. static  int         arithConvCost(var_types src, var_types dst)
  1791. {
  1792.     assert(src >= convCostTypeMin);
  1793.     assert(src <= convCostTypeMax);
  1794.     assert(dst >= convCostTypeMin);
  1795.     assert(dst <= convCostTypeMax);
  1796.  
  1797.     return arithCost[src - convCostTypeMin]
  1798.                     [dst - convCostTypeMin];
  1799. }
  1800.  
  1801. /*****************************************************************************
  1802.  *
  1803.  *  Convert the given expression to the specified type, if possible.
  1804.  */
  1805.  
  1806. Tree                compiler::cmpCoerceExpr(Tree   expr,
  1807.                                             TypDef type, bool explicitCast)
  1808. {
  1809.     unsigned        kind;
  1810.     unsigned        flags  = 0;
  1811.  
  1812.     TypDef          srcType = expr->tnType;
  1813.     TypDef          dstType = type;
  1814.  
  1815.     var_types       srcVtyp;
  1816.     var_types       dstVtyp;
  1817.  
  1818. //  static int x; if (++x == 0) forceDebugBreak();
  1819.  
  1820. AGAIN:
  1821.  
  1822.     assert(expr->tnVtyp != TYP_TYPEDEF);
  1823.  
  1824.     /* Are the types identical? */
  1825.  
  1826.     if  (srcType == dstType)
  1827.     {
  1828.         /* The result of a coercion is never an lvalue */
  1829.  
  1830.         expr->tnFlags &= ~TNF_LVALUE;
  1831.         expr->tnFlags |=  TNF_BEEN_CAST;
  1832.  
  1833.         return expr;
  1834.     }
  1835.  
  1836.     srcVtyp = srcType->tdTypeKindGet();
  1837.     dstVtyp = dstType->tdTypeKindGet();
  1838.  
  1839.     /* Have we had errors within the expression? */
  1840.  
  1841.     if  (srcVtyp == TYP_UNDEF)
  1842.         return expr;
  1843.  
  1844.     /* Are the types identical? */
  1845.  
  1846.     if  (srcVtyp == dstVtyp)
  1847.     {
  1848.         if  (cmpGlobalST->stMatchTypes(srcType, dstType))
  1849.         {
  1850.             /* The result of a coercion is never an lvalue */
  1851.  
  1852.             expr->tnFlags &= ~TNF_LVALUE;
  1853.  
  1854.             return expr;
  1855.         }
  1856.     }
  1857.  
  1858. //  printf("Cast from '%s'\n", cmpGlobalST->stTypeName(expr->tnType, NULL, NULL, NULL, false));
  1859. //  printf("Cast  to  '%s'\n", cmpGlobalST->stTypeName(        type, NULL, NULL, NULL, false));
  1860.  
  1861.     /* Are both types arithmetic? */
  1862.  
  1863.     if  (varTypeIsArithmetic(dstVtyp) &&
  1864.          varTypeIsArithmetic(srcVtyp))
  1865.     {
  1866.         assert(srcVtyp != dstVtyp);
  1867.  
  1868.     ARITH:
  1869.  
  1870.         /* A widening cast is almost always OK (except conversions to 'wchar') */
  1871.  
  1872.         if  (dstVtyp > srcVtyp)
  1873.         {
  1874.             /* Are we coercing an integer constant? */
  1875.  
  1876.             switch (expr->tnOper)
  1877.             {
  1878.                 bool            uns;
  1879.  
  1880.                 __int32         sv;
  1881.                 __uint32        uv;
  1882.  
  1883.             case TN_CNS_INT:
  1884.  
  1885.                 if  (varTypeIsUnsigned(srcVtyp))
  1886.                 {
  1887.                     uns = true;
  1888.                     uv  = expr->tnIntCon.tnIconVal;
  1889.                 }
  1890.                 else
  1891.                 {
  1892.                     uns = false;
  1893.                     sv  = expr->tnIntCon.tnIconVal;
  1894.                 }
  1895.  
  1896.                 switch (dstVtyp)
  1897.                 {
  1898.                 case TYP_CHAR:
  1899.                 case TYP_UCHAR:
  1900.                 case TYP_SHORT:
  1901.                 case TYP_USHORT:
  1902.                 case TYP_INT:
  1903.                 case TYP_NATINT:
  1904.                 case TYP_NATUINT:
  1905.                     // ISSUE: What about sign and range-check?
  1906.                     break;
  1907.  
  1908.                 case TYP_UINT:
  1909.                     if  (!uns && sv < 0)
  1910.                         cmpWarn(WRNunsConst);
  1911.                     break;
  1912.  
  1913.                 case TYP_LONG:
  1914.                 case TYP_ULONG:
  1915.                     expr->tnOper             = TN_CNS_LNG;
  1916.                     expr->tnLngCon.tnLconVal = uns ? (__int64)uv
  1917.                                                    : (__int64)sv;
  1918.                     break;
  1919.  
  1920.                 case TYP_FLOAT:
  1921.                     expr->tnOper             = TN_CNS_FLT;
  1922.                     expr->tnFltCon.tnFconVal = uns ? (float  )uv
  1923.                                                    : (float  )sv;
  1924.                     break;
  1925.  
  1926.                 case TYP_DOUBLE:
  1927.                     expr->tnOper             = TN_CNS_DBL;
  1928.                     expr->tnDblCon.tnDconVal = uns ? (double )uv
  1929.                                                    : (double )sv;
  1930.                     break;
  1931.  
  1932.                 default:
  1933. #ifdef  DEBUG
  1934.                     cmpParser->parseDispTree(expr);
  1935.                     printf("Cast to type '%s'\n", cmpGlobalST->stTypeName(type, NULL, NULL, NULL, false));
  1936. #endif
  1937.                     UNIMPL(!"unexpected constant type");
  1938.                     break;
  1939.                 }
  1940.  
  1941.             BASH_TYPE:
  1942.  
  1943.                 /* Come here to bash the type of the operand */
  1944.  
  1945.                 expr->tnFlags |=  TNF_BEEN_CAST;
  1946.                 expr->tnFlags &= ~TNF_ADR_IMPLICIT;
  1947.  
  1948. #ifdef  DEBUG
  1949.  
  1950.                 /* Make sure we're not bashing the wrong thing */
  1951.  
  1952.                 if      (expr->tnVtyp == TYP_CLASS)
  1953.                 {
  1954.                     assert(cmpFindStdValType(dstVtyp     ) == expr->tnType);
  1955.                 }
  1956.                 else if (dstVtyp == TYP_CLASS)
  1957.                 {
  1958.                     assert(cmpFindStdValType(expr->tnVtyp) == dstType);
  1959.                 }
  1960.                 else
  1961.                 {
  1962.                     switch (expr->tnOper)
  1963.                     {
  1964.                     case TN_CNS_INT:
  1965.  
  1966.                         assert(expr->tnVtyp != TYP_LONG &&
  1967.                                expr->tnVtyp != TYP_ULONG);
  1968.                         break;
  1969.  
  1970.                     case TN_NULL:
  1971.                         break;
  1972.  
  1973.                     case TN_IND:
  1974.                     case TN_INDEX:
  1975.  
  1976.                         if  (   cmpGetTypeSize(cmpActualType(dstType)) !=
  1977.                                 cmpGetTypeSize(cmpActualType(srcType)))
  1978.                         {
  1979.                             printf("Type size changed:\n");
  1980.  
  1981.                         BAD_BASH:
  1982.  
  1983.                             printf("Casting from '%s'\n", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  1984.                             printf("Casting  to  '%s'\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  1985.                             assert(!"bad bash");
  1986.                         }
  1987.  
  1988.                         if  (varTypeIsUnsigned(cmpActualVtyp(dstType)) !=
  1989.                              varTypeIsUnsigned(cmpActualVtyp(srcType)))
  1990.                         {
  1991.                             printf("Type sign changed:\n");
  1992.                             goto BAD_BASH;
  1993.                         }
  1994.  
  1995.                         // Fall through ...
  1996.  
  1997.                     default:
  1998.                         if  (explicitCast)
  1999.                             cmpChk4ctxChange(expr->tnType, type, 0);
  2000.                         break;
  2001.                     }
  2002.                 }
  2003.  
  2004. #endif
  2005.  
  2006.                 assert(dstType->tdTypeKindGet() == dstVtyp);
  2007.  
  2008.                 expr->tnVtyp   = dstVtyp;
  2009.                 expr->tnType   = dstType;
  2010.  
  2011.                 return expr;
  2012.             }
  2013.  
  2014.             /* Only integer constants may be converted to 'wchar' */
  2015.  
  2016.             if  (dstVtyp != TYP_WCHAR)
  2017.             {
  2018.                 int             cost;
  2019.  
  2020.                 /* Special case: float constants converted 'in place' */
  2021.  
  2022.                 if  (expr->tnOper == TN_CNS_FLT)
  2023.                 {
  2024.                     assert(dstVtyp == TYP_DOUBLE);
  2025.  
  2026.                     expr->tnOper             = TN_CNS_DBL;
  2027.                     expr->tnDblCon.tnDconVal = expr->tnFltCon.tnFconVal;
  2028.                     goto BASH_TYPE;
  2029.                 }
  2030.  
  2031.                 /* Even though "TYP_INT < TYP_UINT" is true, it loses precision */
  2032.  
  2033.                 cost = arithConvCost(srcVtyp, dstVtyp);
  2034.  
  2035.                 if  (cost >= 0 && cost < 20)
  2036.                     goto RET_CAST;
  2037.             }
  2038.         }
  2039.  
  2040.         /* Special case: NULL cast to an integral type */
  2041.  
  2042.         if  (expr->tnOper == TN_NULL)
  2043.             goto BASH_TYPE;
  2044.  
  2045.         /* A narrowing cast is OK so long as it's an explicit one */
  2046.  
  2047.         if  (explicitCast)
  2048.             goto RET_CAST;
  2049.  
  2050.         /* Special case: integer constant */
  2051.  
  2052.         if  (expr->tnOper == TN_CNS_INT && expr->tnVtyp != TYP_ENUM)
  2053.         {
  2054.             /* Try to shrink the value to be as small as possible */
  2055.  
  2056.             expr->tnFlags &= ~TNF_BEEN_CAST; expr = cmpShrinkExpr(expr);
  2057.  
  2058.             if  (expr->tnVtyp != srcVtyp)
  2059.             {
  2060.                 srcType = expr->tnType;
  2061.                 goto AGAIN;
  2062.             }
  2063.         }
  2064.  
  2065.         /* Last chance: in non-pedantic mode let this pass with just a warning */
  2066.  
  2067.         if  (!cmpConfig.ccPedantic)
  2068.         {
  2069.             if  ((srcVtyp == TYP_INT || srcVtyp == TYP_UINT) &&
  2070.                  (dstVtyp == TYP_INT || dstVtyp == TYP_UINT))
  2071.             {
  2072.                 goto RET_CAST;
  2073.             }
  2074.  
  2075.             cmpRecErrorPos(expr); cmpWarn(WRNloseBits, srcType, dstType);
  2076.             goto RET_CAST;
  2077.         }
  2078.  
  2079.         /* This is an illegal implicit cast */
  2080.  
  2081.     ERR_IMP:
  2082.  
  2083.         cmpRecErrorPos(expr);
  2084.  
  2085.         if  (expr->tnOper == TN_NULL && !(expr->tnFlags & TNF_BEEN_CAST))
  2086.             cmpError(ERRbadCastNul,         dstType);
  2087.         else
  2088.             cmpError(ERRbadCastImp, srcType, dstType);
  2089.  
  2090.         return cmpCreateErrNode();
  2091.  
  2092.     ERR_EXP:
  2093.  
  2094.         cmpRecErrorPos(expr);
  2095.  
  2096.         if  (expr->tnOper == TN_NULL && !(expr->tnFlags & TNF_BEEN_CAST))
  2097.             cmpError(ERRbadCastNul,         dstType);
  2098.         else
  2099.             cmpError(ERRbadCastExp, srcType, dstType);
  2100.  
  2101.         return cmpCreateErrNode();
  2102.     }
  2103.  
  2104.     /* Let's see what we're casting to */
  2105.  
  2106.     switch (dstVtyp)
  2107.     {
  2108.         TypDef          base;
  2109.         Tree            conv;
  2110.  
  2111.     case TYP_BOOL:
  2112.  
  2113.         /* Nothing can be converted to 'boolean' in pedantic mode */
  2114.  
  2115.         if  (explicitCast || !cmpConfig.ccPedantic)
  2116.         {
  2117.             if  (varTypeIsArithmetic(srcVtyp))
  2118.             {
  2119.                 /* We're presumably materializing a boolean condition */
  2120.  
  2121.                 if  (expr->tnOper == TN_VAR_SYM)
  2122.                 {
  2123.                     SymDef          memSym = expr->tnVarSym.tnVarSym;
  2124.  
  2125.                     assert(memSym->sdSymKind == SYM_VAR);
  2126.  
  2127.                     if  (memSym->sdVar.sdvBfldInfo.bfWidth == 1 &&
  2128.                          varTypeIsUnsigned(expr->tnVtypGet()))
  2129.                     {
  2130.                         /* The value being cast to boolean is a 1-bit bitfield */
  2131.  
  2132.                         goto BASH_TYPE;
  2133.                     }
  2134.                 }
  2135.  
  2136.                 cmpRecErrorPos(expr); cmpWarn(WRNconvert, srcType, dstType);
  2137.  
  2138.                 return  cmpBooleanize(expr, true);
  2139.             }
  2140.  
  2141.             if  (explicitCast && srcType == cmpObjectRef())
  2142.                 return  cmpUnboxExpr(expr, type);
  2143.         }
  2144.  
  2145.         goto TRY_CONVOP;
  2146.  
  2147.     case TYP_WCHAR:
  2148.  
  2149.         /* An explicit cast is always good, in pedantic mode it's required */
  2150.  
  2151.         if  (explicitCast || !cmpConfig.ccPedantic)
  2152.         {
  2153.             /* Any arithmetic type will do */
  2154.  
  2155.             if  (varTypeIsArithmetic(srcVtyp))
  2156.                 goto RET_CAST;
  2157.  
  2158.             if  (explicitCast && srcType == cmpObjectRef())
  2159.                 return  cmpUnboxExpr(expr, type);
  2160.         }
  2161.  
  2162.         /* Also allow integer constant 0 and character literals */
  2163.  
  2164.         if  (expr->tnOper == TN_CNS_INT && (srcVtyp == TYP_CHAR || !expr->tnIntCon.tnIconVal))
  2165.         {
  2166.             goto BASH_TYPE;
  2167.         }
  2168.  
  2169.         goto TRY_CONVOP;
  2170.  
  2171.     case TYP_ENUM:
  2172.  
  2173.         /* We allow enum's to promote to integer types */
  2174.  
  2175.         if  (explicitCast)
  2176.         {
  2177.             var_types       svtp = cmpActualVtyp(srcType);
  2178.             var_types       dvtp = cmpActualVtyp(dstType);
  2179.  
  2180.             /* Make sure the target type isn't too small */
  2181.  
  2182.             if  (dvtp >= svtp || (explicitCast && varTypeIsArithmetic(srcVtyp)))
  2183.             {
  2184.                 /* It's OK to just bash the type if the sign/size match */
  2185.  
  2186.                 if  (symTab::stIntrTypeSize(dvtp) == symTab::stIntrTypeSize(svtp) &&
  2187.                           varTypeIsUnsigned(dvtp) ==      varTypeIsUnsigned(svtp))
  2188.                 {
  2189.                     goto BASH_TYPE;
  2190.                 }
  2191.  
  2192.                 /* Can't just bash the expression, will have to create a cast node */
  2193.  
  2194.                 goto RET_CAST;
  2195.             }
  2196.         }
  2197.  
  2198.         // Fall through ....
  2199.  
  2200.     case TYP_CHAR:
  2201.     case TYP_UCHAR:
  2202.     case TYP_SHORT:
  2203.     case TYP_USHORT:
  2204.     case TYP_INT:
  2205.     case TYP_UINT:
  2206.     case TYP_NATINT:
  2207.     case TYP_NATUINT:
  2208.     case TYP_LONG:
  2209.     case TYP_ULONG:
  2210.  
  2211.         /* It's OK to convert from enum's  */
  2212.  
  2213.         if  (srcVtyp == TYP_ENUM && dstVtyp != TYP_ENUM)
  2214.         {
  2215.             /* Get hold of the underlying type of the enum */
  2216.  
  2217.             base = srcType->tdEnum.tdeIntType;
  2218.  
  2219.             /* If this is an explicit case, it's definitely OK */
  2220.  
  2221.             if  (explicitCast)
  2222.             {
  2223.                 expr->tnType = srcType = base;
  2224.                 expr->tnVtyp = base->tdTypeKindGet();
  2225.                 goto AGAIN;
  2226.             }
  2227.  
  2228.             /* Make sure the target type isn't too small */
  2229.  
  2230.             srcVtyp = base->tdTypeKindGet();
  2231.  
  2232.             if  (srcVtyp == dstVtyp)
  2233.                 goto BASH_TYPE;
  2234.             else
  2235.                 goto ARITH;
  2236.         }
  2237.  
  2238.         /* In unsafe mode it's OK to explicitly cast between integer and pointer types */
  2239.  
  2240.         if  (srcVtyp == TYP_PTR && explicitCast)
  2241.         {
  2242.             if  (cmpConfig.ccSafeMode)
  2243.                 cmpError(ERRunsafeCast, srcType, dstType);
  2244.  
  2245.             if  (symTab::stIntrTypeSize(srcVtyp) == symTab::stIntrTypeSize(dstVtyp))
  2246.                 goto BASH_TYPE;
  2247.             else
  2248.                 goto RET_CAST;
  2249.         }
  2250.  
  2251.         // Fall through ....
  2252.  
  2253.     case TYP_FLOAT:
  2254.     case TYP_DOUBLE:
  2255.     case TYP_LONGDBL:
  2256.  
  2257.         /* An cast from 'wchar' is OK if non-pedantic or explicit */
  2258.  
  2259.         if  (srcVtyp == TYP_WCHAR)
  2260.         {
  2261.             if  (explicitCast || !cmpConfig.ccPedantic)
  2262.                 goto RET_CAST;
  2263.         }
  2264.  
  2265.         /* 'bool' can be converted in non-pedantic mode */
  2266.  
  2267.         if  (srcVtyp == TYP_BOOL && !cmpConfig.ccPedantic)
  2268.         {
  2269.             if  (!explicitCast)
  2270.                 cmpWarn(WRNconvert, srcType, dstType);
  2271.  
  2272.             goto RET_CAST;
  2273.         }
  2274.  
  2275.         if  (explicitCast)
  2276.         {
  2277.             /* "NULL" can be explicitly cast to an integer type */
  2278.  
  2279.             if  (expr->tnOper == TN_NULL && !(expr->tnFlags & TNF_BEEN_CAST))
  2280.                 goto BASH_TYPE;
  2281.  
  2282.             /* Explicit cast from Object is unboxing */
  2283.  
  2284.             if  (srcType == cmpObjectRef())
  2285.                 return  cmpUnboxExpr(expr, type);
  2286.  
  2287.             /* Allow explicit cast of unmanaged string literal to integer */
  2288.  
  2289.             if  (expr->tnOper == TN_CNS_STR && !(expr->tnFlags & TNF_BEEN_CAST))
  2290.             {
  2291.                 if  (!(expr->tnFlags & TNF_STR_STR))
  2292.                     goto BASH_TYPE;
  2293.             }
  2294.         }
  2295.  
  2296.     TRY_CONVOP:
  2297.  
  2298.         /* Last chance: look for an overloaded operator */
  2299.  
  2300.         if  (srcVtyp == TYP_CLASS)
  2301.         {
  2302.             conv = cmpCheckConvOper(expr, NULL, dstType, explicitCast);
  2303.             if  (conv)
  2304.                 return  conv;
  2305.  
  2306.             if  (srcType->tdIsIntrinsic && dstVtyp < TYP_lastIntrins)
  2307.             {
  2308.                 var_types       cvtp = (var_types)srcType->tdClass.tdcIntrType;
  2309.  
  2310.                 /* Can we convert to the corresponding intrinsic type? */
  2311.  
  2312.                 if  (cvtp != TYP_UNDEF)
  2313.                 {
  2314.                     if  (cvtp == dstVtyp)
  2315.                         goto BASH_TYPE;
  2316.  
  2317.                     srcType = cmpGlobalST->stIntrinsicType(cvtp);
  2318.                     expr    = cmpCoerceExpr(expr, srcType, explicitCast);
  2319.                     goto AGAIN;
  2320.                 }
  2321.             }
  2322.         }
  2323.  
  2324.     ERR:
  2325.  
  2326.         if  (explicitCast)
  2327.             goto ERR_EXP;
  2328.         else
  2329.             goto ERR_IMP;
  2330.  
  2331.     case TYP_VOID:
  2332.  
  2333.         /* Anything can be converted to 'void' */
  2334.  
  2335.         goto RET_CAST;
  2336.  
  2337.     case TYP_PTR:
  2338.  
  2339.         if  (explicitCast)
  2340.         {
  2341.             if  (cmpConfig.ccSafeMode)
  2342.                 cmpError(ERRunsafeCast, srcType, dstType);
  2343.  
  2344.             /* Any pointer can be converted to any other via an explicit cast */
  2345.  
  2346.             if  (srcVtyp == TYP_PTR)
  2347.                 goto BASH_TYPE;
  2348.  
  2349.             /* In unsafe mode it's OK to explicitly cast between integers and pointers */
  2350.  
  2351.             if  (varTypeIsIntegral(srcVtyp) && !cmpConfig.ccPedantic)
  2352.             {
  2353.                 if  (symTab::stIntrTypeSize(srcVtyp) == symTab::stIntrTypeSize(dstVtyp))
  2354.                     goto BASH_TYPE;
  2355.                 else
  2356.                     goto RET_CAST;
  2357.             }
  2358.         }
  2359.  
  2360.         /* Special case - string literal passed to "char *" or "void *" */
  2361.  
  2362.         if  (srcVtyp == TYP_REF)
  2363.         {
  2364.             if  (cmpMakeRawString(expr, dstType))
  2365.                 goto BASH_TYPE;
  2366.         }
  2367.  
  2368.         // Fall through ....
  2369.  
  2370.     case TYP_REF:
  2371.  
  2372.         /* Classes can be converted to classes under some circumstances */
  2373.  
  2374.         if  (srcVtyp == dstVtyp)
  2375.         {
  2376.             TypDef          oldBase;
  2377.             TypDef          newBase;
  2378.  
  2379.             oldBase = cmpGetRefBase(srcType); if  (!oldBase) return cmpCreateErrNode();
  2380.             newBase = cmpGetRefBase(dstType); if  (!newBase) return cmpCreateErrNode();
  2381.  
  2382.             /* Unless both are class refs, things don't look too good */
  2383.  
  2384.             if  (oldBase->tdTypeKind != TYP_CLASS ||
  2385.                  newBase->tdTypeKind != TYP_CLASS)
  2386.             {
  2387.                 /* It's always OK to convert "any *" to "void *" */
  2388.  
  2389.                 if  (newBase->tdTypeKind == TYP_VOID)
  2390.                     goto BASH_TYPE;
  2391.  
  2392.                 /* Explicit casts of byrefs are allowed as well */
  2393.  
  2394.                 if  (explicitCast)
  2395.                 {
  2396.                     if  (oldBase->tdTypeKind != TYP_CLASS &&
  2397.                          newBase->tdTypeKind != TYP_CLASS)
  2398.                     {
  2399.                         goto BASH_TYPE;
  2400.                     }
  2401.                 }
  2402.  
  2403.                 goto CHKNCR;
  2404.             }
  2405.  
  2406.             /* "NULL" trivially converts to any reference type */
  2407.  
  2408.             if  (expr->tnOper == TN_NULL && !(expr->tnFlags & TNF_BEEN_CAST))
  2409.                 goto BASH_TYPE;
  2410.  
  2411.             /* Is the target a base class of the source? */
  2412.  
  2413.             if  (cmpIsBaseClass(newBase, oldBase))
  2414.             {
  2415.                 if  (expr->tnOper == TN_NULL)
  2416.                     goto BASH_TYPE;
  2417.  
  2418.                 /* Check for a context change */
  2419.  
  2420. //              printf("Check for ctx [1]: %s", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2421. //              printf(              "-> %s\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2422.  
  2423.                 if  (cmpDiffContext(newBase, oldBase))
  2424.                 {
  2425.                     if  (explicitCast)
  2426.                         flags |= TNF_CTX_CAST;
  2427.                     else
  2428.                         cmpWarn(WRNctxFlavor, srcType, dstType);
  2429.                 }
  2430.  
  2431.                 goto RET_CAST;
  2432.             }
  2433.  
  2434.             /* Is the source a base class of the target? */
  2435.  
  2436.             if  (cmpIsBaseClass(oldBase, newBase))
  2437.             {
  2438.  
  2439.             EXP_CLS:
  2440.  
  2441.                 if  (!explicitCast)
  2442.                     goto CHKNCR;
  2443.  
  2444.                 /* This cast will have to be checked at runtime */
  2445.  
  2446.                 flags |= TNF_CHK_CAST;
  2447.  
  2448.                 /* Check for a context change */
  2449.  
  2450. //              printf("Check for ctx [1]: %s", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2451. //              printf(              "-> %s\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2452.  
  2453.                 if  (cmpDiffContext(newBase, oldBase))
  2454.                     flags |= TNF_CTX_CAST;
  2455.  
  2456.                 goto RET_CAST;
  2457.             }
  2458.  
  2459.             /* Is either type an interface? */
  2460.  
  2461.             if  (oldBase->tdClass.tdcFlavor == STF_INTF)
  2462.                 goto EXP_CLS;
  2463.             if  (newBase->tdClass.tdcFlavor == STF_INTF)
  2464.                 goto EXP_CLS;
  2465.  
  2466.             /* Is either type a generic type argument? */
  2467.  
  2468.             if  (oldBase->tdIsGenArg || newBase->tdIsGenArg)
  2469.             {
  2470.                 // UNDONE: If the generic type has a strong-enough constraint,
  2471.                 // UNDONE: the cast may not need to be checked at runtime.
  2472.  
  2473.                 goto EXP_CLS;
  2474.             }
  2475.  
  2476.             /* Are both delegates? */
  2477.  
  2478.             if  (oldBase->tdClass.tdcFlavor == STF_DELEGATE &&
  2479.                  newBase->tdClass.tdcFlavor == STF_DELEGATE)
  2480.             {
  2481.                 /* If the referenced types are identical, we're OK */
  2482.  
  2483.                 if  (cmpGlobalST->stMatchTypes(oldBase, newBase))
  2484.                     goto BASH_TYPE;
  2485.             }
  2486.         }
  2487.  
  2488.     CHKNCR:
  2489.  
  2490.         if  (dstVtyp == TYP_REF && srcVtyp == TYP_ARRAY)
  2491.         {
  2492.             /* An array may be converted to 'Object' */
  2493.  
  2494.             if  (dstType == cmpObjectRef())
  2495.                 goto BASH_TYPE;
  2496.  
  2497.             /* An array may be converted to 'Array' or to its parents */
  2498.  
  2499.             expr->tnType   = srcType = cmpArrayRef();
  2500.             expr->tnVtyp   = TYP_REF;
  2501.             expr->tnFlags |= TNF_BEEN_CAST;
  2502.  
  2503.             if  (srcType == dstType)
  2504.                 return  expr;
  2505.  
  2506.             goto AGAIN;
  2507.         }
  2508.  
  2509.         /* Special case: 'null' converts to any class ref type */
  2510.  
  2511.         if  (expr->tnOper == TN_NULL && !(expr->tnFlags & TNF_BEEN_CAST))
  2512.             goto BASH_TYPE;
  2513.  
  2514.         if  (type == cmpRefTpObject)
  2515.         {
  2516.             /* Any managed class ref converts to Object */
  2517.  
  2518.             if  (srcVtyp == TYP_REF)
  2519.             {
  2520.                 TypDef          srcBase;
  2521.  
  2522.                 srcBase = cmpGetRefBase(srcType);
  2523.                 if  (!srcBase)
  2524.                     return cmpCreateErrNode();
  2525.  
  2526.                 if  (srcBase->tdTypeKind == TYP_CLASS && srcBase->tdIsManaged)
  2527.                 {
  2528.                     /* Check for a context change */
  2529.  
  2530. //                  printf("Check for ctx [1]: %s", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2531. //                  printf(              "-> %s\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2532.  
  2533.                     if  (cmpDiffContext(srcBase, cmpClassObject->sdType))
  2534.                     {
  2535.                         if  (explicitCast)
  2536.                         {
  2537.                             flags |= TNF_CTX_CAST;
  2538.                             goto RET_CAST;
  2539.                         }
  2540.  
  2541.                         cmpWarn(WRNctxFlavor, srcType, dstType);
  2542.                     }
  2543.  
  2544.                     goto BASH_TYPE;
  2545.                 }
  2546.             }
  2547.  
  2548.             /* Check for a user-defined conversion if value type */
  2549.  
  2550.             if  (srcVtyp == TYP_CLASS)
  2551.             {
  2552.                 conv = cmpCheckConvOper(expr, NULL, dstType, explicitCast);
  2553.                 if  (conv)
  2554.                     return  conv;
  2555.             }
  2556.  
  2557.             if  (explicitCast)
  2558.             {
  2559.                 if  (srcVtyp != TYP_FNC && srcVtyp != TYP_VOID && srcVtyp != TYP_PTR)
  2560.                     return  cmpCreateExprNode(NULL, TN_BOX, type, expr);
  2561.             }
  2562.         }
  2563.  
  2564.         if  (expr->tnOper == TN_CNS_INT &&   srcVtyp == TYP_INT
  2565.                                         &&   dstVtyp == TYP_PTR
  2566.                                         &&   expr->tnIntCon.tnIconVal == 0
  2567.                                         && !(expr->tnFlags & TNF_BEEN_CAST))
  2568.         {
  2569.             /* In non-pedantic mode we let this through with a warning */
  2570.  
  2571.             if  (!cmpConfig.ccPedantic)
  2572.             {
  2573.                 cmpRecErrorPos(expr);
  2574.                 cmpWarn(WRNzeroPtr);
  2575.                 goto BASH_TYPE;
  2576.             }
  2577.         }
  2578.  
  2579.         /* Look for a user-defined conversion operator if we have a struct */
  2580.  
  2581.         if  (srcVtyp == TYP_CLASS)
  2582.         {
  2583.             TypDef          btyp;
  2584.  
  2585.             conv = cmpCheckConvOper(expr, NULL, dstType, explicitCast);
  2586.             if  (conv)
  2587.                 return  conv;
  2588.  
  2589.             /* Does the struct implement the target type? */
  2590.  
  2591.             btyp = cmpGetRefBase(dstType);
  2592.  
  2593.             if  (btyp && btyp->tdTypeKind == TYP_CLASS && cmpIsBaseClass(btyp, srcType))
  2594.             {
  2595.                 /* Box the struct and cast the result */
  2596.  
  2597.                 srcType = cmpRefTpObject;
  2598.                 expr    = cmpCreateExprNode(NULL, TN_BOX, srcType, expr);
  2599.  
  2600.                 /* The cast from object has to be explicit */
  2601.  
  2602.                 explicitCast = true;
  2603.  
  2604.                 goto AGAIN;
  2605.             }
  2606.  
  2607.         }
  2608.  
  2609. #if 0
  2610.  
  2611.         /* Look for an overloaded operator in the class */
  2612.  
  2613.         if  (dstVtyp == TYP_REF)
  2614.         {
  2615.             conv = cmpCheckConvOper(expr, NULL, dstType, explicitCast);
  2616.             if  (conv)
  2617.                 return  conv;
  2618.         }
  2619.  
  2620. #endif
  2621.  
  2622.         /* Last chance - check for box-and-cast, the most wonderful thing ever invented */
  2623.  
  2624.         if  (dstVtyp == TYP_REF && srcVtyp <  TYP_lastIntrins
  2625.                                 && srcVtyp != TYP_VOID)
  2626.         {
  2627.             TypDef          boxer = cmpFindStdValType(srcVtyp);
  2628.  
  2629.             if  (boxer && cmpIsBaseClass(cmpGetRefBase(dstType), boxer))
  2630.             {
  2631.                 expr = cmpCreateExprNode(NULL, TN_BOX, boxer->tdClass.tdcRefTyp, expr);
  2632.                 goto RET_CAST;
  2633.             }
  2634.         }
  2635.  
  2636.         goto ERR;
  2637.  
  2638.     case TYP_ARRAY:
  2639.  
  2640.         /* Are we converting an array to another one? */
  2641.  
  2642.         if  (srcVtyp == TYP_ARRAY)
  2643.         {
  2644.             TypDef          srcBase;
  2645.             TypDef          dstBase;
  2646.  
  2647.             /* Do we have a matching number dimensions? */
  2648.  
  2649.             if  (srcType->tdArr.tdaDcnt != dstType->tdArr.tdaDcnt)
  2650.                 goto ERR;
  2651.  
  2652.             /* Check the element types of the arrays */
  2653.  
  2654.             srcBase = cmpDirectType(srcType->tdArr.tdaElem);
  2655.             dstBase = cmpDirectType(dstType->tdArr.tdaElem);
  2656.  
  2657.             /* If the element types are identical, we're OK */
  2658.  
  2659.             if  (cmpGlobalST->stMatchTypes(srcBase, dstBase))
  2660.                 goto RET_CAST;
  2661.  
  2662.             /* Are these both arrays of classes? */
  2663.  
  2664.             if  (srcBase->tdTypeKind == TYP_REF &&
  2665.                  dstBase->tdTypeKind == TYP_REF)
  2666.             {
  2667.                 /* Pretend we had classes to begin with */
  2668.  
  2669.                 srcType = srcBase;
  2670.                 dstType = dstBase;
  2671.  
  2672.                 goto AGAIN;
  2673.             }
  2674.  
  2675.             /* Check if one is a subtype of the other */
  2676.  
  2677.             if  (symTab::stMatchArrays(srcType, dstType, true))
  2678.                 goto RET_CAST;
  2679.  
  2680.             goto ERR;
  2681.         }
  2682.  
  2683.         /* 'Object' and 'Array' can sometimes be converted to an array */
  2684.  
  2685.         if  (srcVtyp == TYP_REF)
  2686.         {
  2687.             if  (srcType == cmpArrayRef()) ////////// && explicitCast)   disabled for now, tests break!
  2688.             {
  2689.                 flags |= TNF_CHK_CAST;
  2690.                 goto RET_CAST;
  2691.             }
  2692.  
  2693.             if  (srcType == cmpObjectRef())
  2694.             {
  2695.                 /* Special case: 'null' converts to an array type */
  2696.  
  2697.                 if  (expr->tnOper == TN_NULL)
  2698.                     goto BASH_TYPE;
  2699.  
  2700.                 if  (explicitCast)
  2701.                 {
  2702.                     flags |= TNF_CHK_CAST;
  2703.                     goto RET_CAST;
  2704.                 }
  2705.             }
  2706.         }
  2707.  
  2708.         goto ERR;
  2709.  
  2710.     case TYP_UNDEF:
  2711.         return cmpCreateErrNode();
  2712.  
  2713.     case TYP_CLASS:
  2714.  
  2715.         /* Check for unboxing from Object to a struct type */
  2716.  
  2717.         if  (srcType == cmpObjectRef() && explicitCast)
  2718.             return  cmpUnboxExpr(expr, type);
  2719.  
  2720.         /* Look for a user-defined conversion operator */
  2721.  
  2722.         conv = cmpCheckConvOper(expr, NULL, dstType, explicitCast);
  2723.         if  (conv)
  2724.             return  conv;
  2725.  
  2726.         /* Check for a downcast */
  2727.  
  2728.         if  (srcVtyp == TYP_REF && explicitCast)
  2729.         {
  2730.             TypDef          srcBase = cmpGetRefBase(srcType);
  2731.  
  2732.             /* Is the source a base class of the target? */
  2733.  
  2734.             if  (srcBase && srcBase->tdTypeKind == TYP_CLASS
  2735.                          && cmpIsBaseClass(srcBase, dstType))
  2736.             {
  2737.                 /* Simply unbox the expression */
  2738.  
  2739.                 return  cmpUnboxExpr(expr, dstType);
  2740.             }
  2741.         }
  2742.  
  2743.         /* Last chance - let's confuse structs and intrinsics */
  2744.  
  2745.         if  (srcVtyp < TYP_lastIntrins)
  2746.         {
  2747.             var_types       cvtp = (var_types)dstType->tdClass.tdcIntrType;
  2748.  
  2749.             /* Can we convert to the corresponding intrinsic type? */
  2750.  
  2751.             if  (cvtp != TYP_UNDEF)
  2752.             {
  2753.                 if  (cvtp == srcVtyp)
  2754.                     goto BASH_TYPE;
  2755. //                  goto RET_CAST;
  2756.  
  2757.                 dstType = cmpGlobalST->stIntrinsicType(cvtp);
  2758.                 expr    = cmpCoerceExpr(expr, dstType, explicitCast);
  2759.                 goto AGAIN;
  2760.             }
  2761.         }
  2762.  
  2763.         goto ERR;
  2764.  
  2765.     case TYP_TYPEDEF:
  2766.  
  2767.         dstType = dstType->tdTypedef.tdtType;
  2768.         goto AGAIN;
  2769.  
  2770.     case TYP_REFANY:
  2771.         if  (expr->tnOper != TN_ADDROF || (expr->tnFlags & TNF_ADR_IMPLICIT))
  2772.             goto ERR;
  2773.         goto RET_CAST;
  2774.  
  2775.     default:
  2776.  
  2777. #ifdef  DEBUG
  2778.         printf("Casting from '%s'\n", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2779.         printf("Casting  to  '%s'\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2780. #endif
  2781.         assert(!"unhandled target type in compiler::cmpCoerceExpr()");
  2782.     }
  2783.  
  2784.     /* See what we're casting from */
  2785.  
  2786.     switch (srcVtyp)
  2787.     {
  2788.     case TYP_BOOL:
  2789.     case TYP_VOID:
  2790.  
  2791.         /* 'boolean' or 'void' can never be converted to anything */
  2792.  
  2793.         goto ERR_EXP;
  2794.  
  2795.     default:
  2796. #ifdef  DEBUG
  2797.         printf("Casting from '%s'\n", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2798.         printf("Casting  to  '%s'\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2799. #endif
  2800.         assert(!"unhandled source type in compiler::cmpCoerceExpr()");
  2801.     }
  2802.  
  2803. RET_CAST:
  2804.  
  2805. //  if  (expr->tnOper == TN_NULL)  forceDebugBreak();
  2806.  
  2807.     /* Don't leave any enum's around */
  2808.  
  2809.     if  (expr->tnVtyp == TYP_ENUM)
  2810.     {
  2811.         expr->tnType = expr->tnType->tdEnum.tdeIntType;
  2812.         expr->tnVtyp = expr->tnType->tdTypeKindGet();
  2813.     }
  2814.  
  2815. #ifndef NDEBUG
  2816.     if  (explicitCast) cmpChk4ctxChange(expr->tnType, type, flags);
  2817. #endif
  2818.  
  2819.     /* Remember whether the operand is a constant or not */
  2820.  
  2821.     kind = expr->tnOperKind();
  2822.  
  2823.     /* Create the cast expression */
  2824.  
  2825.     expr = cmpCreateExprNode(NULL, TN_CAST, type, expr);
  2826.     expr->tnFlags |= flags;
  2827.  
  2828.     /* Casts to 'bool' must be done differently */
  2829.  
  2830.     assert(expr->tnVtyp != TYP_BOOL || srcVtyp == TYP_CLASS && cmpFindStdValType(TYP_BOOL) == srcType);
  2831.  
  2832.     if  (kind & TNK_CONST)
  2833.     {
  2834.         switch (expr->tnOp.tnOp1->tnOper)
  2835.         {
  2836.         case TN_CNS_INT: expr = cmpFoldIntUnop(expr); break;
  2837.         case TN_CNS_LNG: expr = cmpFoldLngUnop(expr); break;
  2838.         case TN_CNS_FLT: expr = cmpFoldFltUnop(expr); break;
  2839.         case TN_CNS_DBL: expr = cmpFoldDblUnop(expr); break;
  2840.  
  2841.         case TN_NULL:
  2842.         case TN_CNS_STR: break;
  2843.  
  2844.         default: NO_WAY(!"unexpected const type");
  2845.         }
  2846.     }
  2847.  
  2848.     return  expr;
  2849. }
  2850.  
  2851. /*****************************************************************************
  2852.  *
  2853.  *  We have a situation where a pointer is expected and an expression was
  2854.  *  supplied that appears to have a reference type. We check to see whether
  2855.  *  the expression is a string literal, and if so we make it into a "raw"
  2856.  *  string (i.e. we change it from "String &" to "char *" or "wchar *").
  2857.  */
  2858.  
  2859. bool                compiler::cmpMakeRawStrLit(Tree     expr,
  2860.                                                TypDef   type, bool chkOnly)
  2861. {
  2862.     var_types       btp;
  2863.  
  2864.     /* We expect the caller to have checked some things already */
  2865.  
  2866.     assert(expr->tnVtyp     == TYP_REF);
  2867.     assert(type->tdTypeKind == TYP_PTR);
  2868.  
  2869.     assert(expr->tnOper == TN_CNS_STR || expr->tnOper == TN_QMARK);
  2870.  
  2871.     /* If the type of the expression has been set explicitly, no can do */
  2872.  
  2873.     if  (expr->tnFlags & (TNF_BEEN_CAST|TNF_STR_STR))
  2874.         return  false;
  2875.  
  2876.     /* Make sure the target type is acceptable for a string */
  2877.  
  2878.     btp = cmpGetRefBase(type)->tdTypeKindGet();
  2879.  
  2880.     switch (btp)
  2881.     {
  2882.     case TYP_CHAR:
  2883.         if  (expr->tnFlags & TNF_STR_WIDE)
  2884.             return  false;
  2885.         break;
  2886.  
  2887.     case TYP_WCHAR:
  2888.         if  (expr->tnFlags & TNF_STR_ASCII)
  2889.             return  false;
  2890.         break;
  2891.  
  2892.     case TYP_VOID:
  2893.         if  (!(expr->tnFlags & (TNF_STR_ASCII|TNF_STR_WIDE|TNF_STR_STR)))
  2894.         {
  2895.             if  (!chkOnly)
  2896.                 expr->tnFlags |= TNF_STR_ASCII; // HACK - default for strlit is ANSI
  2897.  
  2898. //          return  false;
  2899.         }
  2900.         break;
  2901.  
  2902.     default:
  2903.         return  false;
  2904.     }
  2905.  
  2906.     /* If we have ?:, there is more checking to be done */
  2907.  
  2908.     if  (expr->tnOper == TN_QMARK)
  2909.     {
  2910.         Tree            col1 = expr->tnOp.tnOp2->tnOp.tnOp1;
  2911.         Tree            col2 = expr->tnOp.tnOp2->tnOp.tnOp2;
  2912.  
  2913.         assert(col1 && cmpIsStringVal(col1));
  2914.         assert(col2 && cmpIsStringVal(col2));
  2915.  
  2916.         /* Check for the obvious case of <cond ? "str1" : "str2" > */
  2917.  
  2918.         if  (col1->tnOper != TN_CNS_STR || (col1->tnFlags & TNF_BEEN_CAST))
  2919.         {
  2920.             if  (chkOnly)
  2921.             {
  2922.                 if  (cmpConversionCost(col1, type) < 0)
  2923.                     return  false;
  2924.             }
  2925.             else
  2926.                 col1 = cmpCoerceExpr(col1, type, true);
  2927.         }
  2928.  
  2929.         if  (col2->tnOper != TN_CNS_STR)
  2930.         {
  2931.             if  (chkOnly)
  2932.             {
  2933.                 if  (cmpConversionCost(col2, type) < 0)
  2934.                     return  false;
  2935.             }
  2936.             else
  2937.                 col2 = cmpCoerceExpr(col2, type, true);
  2938.         }
  2939.  
  2940.         /* Bash the types of each sub-operand */
  2941.  
  2942.         col1->tnVtyp = col2->tnVtyp = TYP_PTR;
  2943.         col1->tnType = col2->tnType = type;
  2944.     }
  2945.  
  2946.     /* Looks good, bash the type of the expression and return */
  2947.  
  2948.     if  (!chkOnly)
  2949.     {
  2950.         expr->tnVtyp = TYP_PTR;
  2951.         expr->tnType = type;
  2952.     }
  2953.  
  2954.     return  true;
  2955. }
  2956.  
  2957. /*****************************************************************************
  2958.  *
  2959.  *  Return the "cost" of converting the actual argument value 'srcExpr' to
  2960.  *  the formal argument type 'dstType' - the higher the number, the more
  2961.  *  work it is to convert, with -1 meaning the conversion is impossible.
  2962.  */
  2963.  
  2964. int                 compiler::cmpConversionCost(Tree    srcExpr,
  2965.                                                 TypDef  dstType, bool noUserConv)
  2966. {
  2967.     TypDef          srcType = srcExpr->tnType;
  2968.  
  2969.     var_types       srcVtyp;
  2970.     var_types       dstVtyp;
  2971.  
  2972.     int             cost;
  2973.  
  2974. //  printf("srcType = %s\n", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  2975. //  printf("dstType = %s\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  2976.  
  2977. AGAIN:
  2978.  
  2979.     srcVtyp = srcType->tdTypeKindGet();
  2980.     dstVtyp = dstType->tdTypeKindGet();
  2981.  
  2982.     /* Is either type a typedef? */
  2983.  
  2984.     if  (srcVtyp == TYP_TYPEDEF)
  2985.     {
  2986.         srcType = srcType->tdTypedef.tdtType;
  2987.         srcVtyp = srcType->tdTypeKindGet();
  2988.     }
  2989.  
  2990.     if  (dstVtyp == TYP_TYPEDEF)
  2991.     {
  2992.         dstType = dstType->tdTypedef.tdtType;
  2993.         dstVtyp = dstType->tdTypeKindGet();
  2994.     }
  2995.  
  2996.     /* Are the types identical? */
  2997.  
  2998.     if  (srcVtyp == dstVtyp)
  2999.     {
  3000.         if  (srcVtyp <= TYP_lastIntrins)
  3001.             return  0;
  3002.  
  3003.         if  (cmpGlobalST->stMatchTypes(srcType, dstType))
  3004.         {
  3005.             /* The following is rather absurd, but whatever */
  3006.  
  3007.             if  (srcExpr->tnOper != TN_NULL)
  3008.                 return 0;
  3009.         }
  3010.     }
  3011.  
  3012.     /* Are both types arithmetic? */
  3013.  
  3014.     if  (varTypeIsArithmetic(dstVtyp) &&
  3015.          varTypeIsArithmetic(srcVtyp))
  3016.     {
  3017.         assert(srcVtyp != dstVtyp);
  3018.  
  3019.     ARITH:
  3020.  
  3021.         /* Compute the cost from the table */
  3022.  
  3023.         cost = arithConvCost(srcVtyp, dstVtyp);
  3024.  
  3025.         if  (cost >= 20 && cmpConfig.ccPedantic)
  3026.             cost = -1;
  3027.  
  3028.         return  cost;
  3029.     }
  3030.     else if (srcVtyp == TYP_ENUM && varTypeIsArithmetic(dstVtyp))
  3031.     {
  3032.         unsigned        cost;
  3033.  
  3034.         /* We're converting an enum to an arithmetic type */
  3035.  
  3036.         cost = arithConvCost(srcType->tdEnum.tdeIntType->tdTypeKindGet(), dstVtyp);
  3037.  
  3038.         return  cost + 1;
  3039.     }
  3040.     else if (srcVtyp == TYP_BOOL && !cmpConfig.ccPedantic)
  3041.     {
  3042.         /* Promoting 'bool' to an arithmetic type is not exactly a big deal */
  3043.  
  3044.         if  (varTypeIsArithmetic(dstVtyp))
  3045.             return  2;
  3046.     }
  3047.  
  3048.     /* Let's see what we're casting to */
  3049.  
  3050.     switch (dstVtyp)
  3051.     {
  3052.         unsigned        cost;
  3053.  
  3054.     case TYP_WCHAR:
  3055.  
  3056.         /* Special case: a character literal */
  3057.  
  3058.         if  (srcVtyp == TYP_CHAR && srcExpr->tnOper == TN_CNS_INT)
  3059.         {
  3060.             if  (!(srcExpr->tnFlags & TNF_BEEN_CAST))
  3061.             {
  3062.                 return  0;
  3063.             }
  3064.         }
  3065.  
  3066.         // Fall through ....
  3067.  
  3068.     case TYP_BOOL:
  3069.     case TYP_CHAR:
  3070.     case TYP_UCHAR:
  3071.     case TYP_SHORT:
  3072.     case TYP_USHORT:
  3073.     case TYP_INT:
  3074.     case TYP_NATINT:
  3075.     case TYP_NATUINT:
  3076.     case TYP_UINT:
  3077.     case TYP_LONG:
  3078.     case TYP_ULONG:
  3079.     case TYP_FLOAT:
  3080.     case TYP_DOUBLE:
  3081.     case TYP_LONGDBL:
  3082.  
  3083.         if  (srcVtyp == TYP_WCHAR || srcVtyp == TYP_BOOL)
  3084.         {
  3085.             if  (!cmpConfig.ccPedantic)
  3086.                 goto ARITH;
  3087.         }
  3088.  
  3089.         return -1;
  3090.  
  3091.     case TYP_REF:
  3092.     case TYP_PTR:
  3093.  
  3094.         /* Classes can be converted to classes under some circumstances */
  3095.  
  3096.         if  (srcVtyp == dstVtyp)
  3097.         {
  3098.             TypDef          srcBase = cmpGetRefBase(srcType);
  3099.             TypDef          dstBase = cmpGetRefBase(dstType);
  3100.  
  3101.             if  (!srcBase)
  3102.             {
  3103.                 /* Special case: 'src' could be an undefined type */
  3104.  
  3105.                 if  (dstType == cmpRefTpObject)
  3106.                     return 2;
  3107.  
  3108.                 return -1;
  3109.             }
  3110.  
  3111.             if  (!dstBase)
  3112.                 return -1;
  3113.  
  3114.             /* Special case: 'null' converts easily to any ref/ptr type */
  3115.  
  3116.             if  (srcExpr->tnOper == TN_NULL && !(srcExpr->tnFlags & TNF_BEEN_CAST))
  3117.             {
  3118.                 unsigned        cost = cmpIsBaseClass(srcBase, dstBase);
  3119.  
  3120. #if 0
  3121. printf("srcBase = %s\n", cmpGlobalST->stTypeName(srcBase, NULL, NULL, NULL, false));
  3122. printf("dstBase = %s\n", cmpGlobalST->stTypeName(dstBase, NULL, NULL, NULL, false));
  3123. printf("cost is   %u\n", cost);
  3124. #endif
  3125.  
  3126.                 /* The following is a horrendous hack */
  3127.  
  3128.                 if  (cost > 10)
  3129.                     return  1;
  3130.                 else
  3131.                     return  10 - cost;
  3132.             }
  3133.  
  3134.             /* Is the target a base class of the source? */
  3135.  
  3136.             if  (srcBase->tdTypeKind == TYP_CLASS &&
  3137.                  dstBase->tdTypeKind == TYP_CLASS)
  3138.             {
  3139.                 if  (srcBase == dstBase)
  3140.                     return  0;
  3141.  
  3142.                 cost = cmpIsBaseClass(dstBase, srcBase);
  3143.                 if  (cost)
  3144.                     return  cost;
  3145.             }
  3146.  
  3147.             /* It's not too bad to convert to "void *" */
  3148.  
  3149.             if  (dstBase->tdTypeKind == TYP_VOID)
  3150.                 return  2;
  3151.  
  3152.             return  -1;
  3153.         }
  3154.  
  3155.         /* An array or method pointer may be converted to 'Object' */
  3156.  
  3157.         if  (dstType == cmpRefTpObject)
  3158.         {
  3159.             if  (srcVtyp == TYP_ARRAY)
  3160.             {
  3161.                 if  (dstType == cmpArrayRef())
  3162.                     return 1;
  3163.                 else
  3164.                     return  2;
  3165.             }
  3166.  
  3167.             if  (srcVtyp == TYP_FNC)
  3168.             {
  3169.                 assert(srcExpr->tnOper == TN_FNC_PTR);
  3170.  
  3171.                 return  2;
  3172.             }
  3173.  
  3174.         }
  3175.  
  3176.         if  (dstVtyp == TYP_PTR)
  3177.         {
  3178.             if  (srcVtyp == TYP_REF)
  3179.             {
  3180.                 /* String literal passed to "char *" or "void *" is also OK */
  3181.  
  3182.                 if  (cmpMakeRawString(srcExpr, dstType, true))
  3183.                     return  1;
  3184.  
  3185.                 /* 'null' converts to any ptr type */
  3186.  
  3187.                 if  (srcExpr->tnOper == TN_NULL && !(srcExpr->tnFlags & TNF_BEEN_CAST))
  3188.                     return 1;
  3189.             }
  3190.  
  3191.             /* Some people insist on using 0 instead of null/NULL */
  3192.  
  3193.             if  (srcVtyp         ==    TYP_INT &&
  3194.                  srcExpr->tnOper == TN_CNS_INT &&   srcExpr->tnIntCon.tnIconVal == 0
  3195.                                                && !(srcExpr->tnFlags & TNF_BEEN_CAST))
  3196.             {
  3197.                 /* In non-pedantic mode we let this through with a warning */
  3198.  
  3199.                 if  (!cmpConfig.ccPedantic)
  3200.                     return  2;
  3201.             }
  3202.         }
  3203.  
  3204.         /* An array may be converted to 'Array' */
  3205.  
  3206.         if  (dstType == cmpArrayRef() && srcVtyp == TYP_ARRAY)
  3207.             return  1;
  3208.  
  3209.         return -1;
  3210.  
  3211.     case TYP_ARRAY:
  3212.  
  3213.         /* Are we converting an array to another one? */
  3214.  
  3215.         if  (srcVtyp == TYP_ARRAY)
  3216.         {
  3217.             TypDef          srcBase;
  3218.             TypDef          dstBase;
  3219.  
  3220.             /* Check the element types of the arrays */
  3221.  
  3222.             srcBase = cmpDirectType(srcType->tdArr.tdaElem);
  3223.             dstBase = cmpDirectType(dstType->tdArr.tdaElem);
  3224.  
  3225.             /* If the element types are identical, we're OK */
  3226.  
  3227.             if  (cmpGlobalST->stMatchTypes(srcBase, dstBase))
  3228.                 return 0;
  3229.  
  3230.             /* Are these both arrays of classes? */
  3231.  
  3232.             if  (srcBase->tdTypeKind == TYP_REF &&
  3233.                  dstBase->tdTypeKind == TYP_REF)
  3234.             {
  3235.                 /* Pretend we had classes to begin with */
  3236.  
  3237.                 srcType = srcBase;
  3238.                 dstType = dstBase;
  3239.  
  3240.                 goto AGAIN;
  3241.             }
  3242.  
  3243.             /* Check if one is a subtype of the other */
  3244.  
  3245.             if  (symTab::stMatchArrays(srcType, dstType, true))
  3246.                 return  1;
  3247.         }
  3248.  
  3249.         /* 'null' converts to an array */
  3250.  
  3251.         if  (srcVtyp == TYP_REF && srcType == cmpRefTpObject)
  3252.         {
  3253.             if  (srcExpr->tnOper == TN_NULL)
  3254.                 return 1;
  3255.         }
  3256.  
  3257.         return -1;
  3258.  
  3259.     case TYP_UNDEF:
  3260.         return -1;
  3261.  
  3262.     case TYP_CLASS:
  3263.  
  3264.         if  (noUserConv)
  3265.             return  -1;
  3266.  
  3267.         if  (cmpCheckConvOper(srcExpr, srcType, dstType, false, &cost))
  3268.             return  cost;
  3269.  
  3270.         return  -1;
  3271.  
  3272.     case TYP_ENUM:
  3273.  
  3274.         /* We already know the source isn't the same type */
  3275.  
  3276.         assert(cmpGlobalST->stMatchTypes(srcType, dstType) == false);
  3277.  
  3278.         /* An explicit conversion is OK if the source type is an arithmetic type */
  3279.  
  3280.         if  (varTypeIsIntegral(srcVtyp))
  3281.         {
  3282.             if  (srcVtyp == TYP_ENUM)
  3283.                 srcVtyp = srcType->tdEnum.tdeIntType->tdTypeKindGet();
  3284.  
  3285.             return  20 + arithConvCost(srcVtyp, dstType->tdEnum.tdeIntType->tdTypeKindGet());
  3286.         }
  3287.  
  3288.         return  -1;
  3289.  
  3290.     case TYP_REFANY:
  3291.         if  (srcExpr->tnOper == TN_ADDROF && !(srcExpr->tnFlags & TNF_ADR_IMPLICIT))
  3292.             return  0;
  3293.  
  3294.         return  -1;
  3295.  
  3296.     default:
  3297.         assert(!"unhandled target type in compiler::cmpConversionCost()");
  3298.     }
  3299.  
  3300.     /* See what we're casting from */
  3301.  
  3302.     switch (srcVtyp)
  3303.     {
  3304.     case TYP_BOOL:
  3305.  
  3306.         /* 'boolean' can never be converted to anything */
  3307.  
  3308.         break;
  3309.  
  3310.     default:
  3311.         assert(!"unhandled source type in compiler::cmpConversionCost()");
  3312.     }
  3313.  
  3314.     return -1;
  3315. }
  3316.  
  3317. /*****************************************************************************
  3318.  *
  3319.  *  If the argsession is a constant, shrink it to the smallest possible type
  3320.  *  that can hold the constant value.
  3321.  */
  3322.  
  3323. Tree                compiler::cmpShrinkExpr(Tree expr)
  3324. {
  3325.     if  (expr->tnOper == TN_CNS_INT ||
  3326.          expr->tnOper == TN_CNS_FLT ||
  3327.          expr->tnOper == TN_CNS_DBL)
  3328.     {
  3329.         var_types       vtp = expr->tnVtypGet();
  3330.  
  3331.         /* Don't touch the thing if it's not an intrinsic type */
  3332.  
  3333.         if  (vtp > TYP_lastIntrins)
  3334.         {
  3335. #if 0
  3336.             TypDef          etp;
  3337.  
  3338.             /* Except for enums, of course */
  3339.  
  3340.             if  (vtp != TYP_ENUM)
  3341.                 return  expr;
  3342.  
  3343.             expr->tnType = etp = expr->tnType->tdEnum.tdeIntType;
  3344.             expr->tnVtyp = vtp = etp->tdTypeKindGet();
  3345. #else
  3346.             return  expr;
  3347. #endif
  3348.         }
  3349.  
  3350.         /* Figure out the smallest size for the constant */
  3351.  
  3352.         expr->tnVtyp = cmpConstSize(expr, vtp);
  3353.         expr->tnType = cmpGlobalST->stIntrinsicType(expr->tnVtypGet());
  3354.     }
  3355.  
  3356.     return  expr;
  3357. }
  3358.  
  3359. /*****************************************************************************
  3360.  *
  3361.  *  Find an appropriate string comparison method.
  3362.  */
  3363.  
  3364. SymDef              compiler::cmpFindStrCompMF(const char *name, bool retBool)
  3365. {
  3366.     ArgDscRec       args;
  3367.     TypDef          type;
  3368.     SymDef          fsym;
  3369.  
  3370.     cmpParser->parseArgListNew(args,
  3371.                                2,
  3372.                                false, cmpRefTpString,
  3373.                                       cmpRefTpString,
  3374.                                       NULL);
  3375.  
  3376.     type  = cmpGlobalST->stNewFncType(args, retBool ? cmpTypeBool
  3377.                                                     : cmpTypeInt);
  3378.  
  3379.     /* Find the appropriate method in class System::String */
  3380.  
  3381.     fsym = cmpGlobalST->stLookupClsSym(cmpGlobalHT->hashString(name),
  3382.                                        cmpClassString);
  3383.     assert(fsym);
  3384.  
  3385.     fsym = cmpCurST->stFindOvlFnc(fsym, type);
  3386.  
  3387.     assert(fsym && fsym->sdIsStatic);
  3388.  
  3389.     return  fsym;
  3390. }
  3391.  
  3392. /*****************************************************************************
  3393.  *
  3394.  *  Call the specified string comparison method.
  3395.  */
  3396.  
  3397. Tree                compiler::cmpCallStrCompMF(Tree expr,
  3398.                                                Tree  op1,
  3399.                                                Tree  op2, SymDef fsym)
  3400. {
  3401.     assert(expr && op1 && op2);
  3402.     assert(fsym && fsym->sdIsMember && fsym->sdSymKind == SYM_FNC && fsym->sdIsStatic);
  3403.  
  3404.     op2 = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, op2, NULL);
  3405.     op1 = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, op1,  op2);
  3406.  
  3407.     expr->tnOper             = TN_FNC_SYM;
  3408.     expr->tnType             = fsym->sdType->tdFnc.tdfRett;
  3409.     expr->tnVtyp             = expr->tnType->tdTypeKindGet();
  3410.     expr->tnFncSym.tnFncSym  = fsym;
  3411.     expr->tnFncSym.tnFncArgs = op1;
  3412.     expr->tnFncSym.tnFncObj  = NULL;
  3413.     expr->tnFncSym.tnFncScp  = NULL;
  3414.  
  3415.     return  expr;
  3416. }
  3417.  
  3418. /*****************************************************************************
  3419.  *
  3420.  *  Given a member function and an argument list, find a matching overload.
  3421.  */
  3422.  
  3423. SymDef              compiler::cmpFindOvlMatch(SymDef fncSym, Tree args,
  3424.                                                              Tree thisArg)
  3425. {
  3426.     int             argCnt   = -1;
  3427.  
  3428.     TypDef          bestTyp;
  3429.     SymDef          bestSym  = NULL;
  3430.     SymDef          moreSym  = NULL;
  3431.  
  3432.     unsigned        btotCost = 99999;
  3433.     int             bestCost = 99999;
  3434.  
  3435.     bool            inBase   = false;
  3436.  
  3437.     SymDef          xtraSym  = NULL;
  3438.  
  3439.     /* Do we have two sets of functions to consider? */
  3440.  
  3441.     if  (!fncSym)
  3442.     {
  3443.         assert(args && args->tnOper == TN_LIST);
  3444.  
  3445.         assert(thisArg->tnOper == TN_LIST);
  3446.         assert(thisArg->tnOp.tnOp1->tnOper == TN_FNC_SYM);
  3447.         assert(thisArg->tnOp.tnOp2->tnOper == TN_FNC_SYM);
  3448.  
  3449.          fncSym = thisArg->tnOp.tnOp1->tnFncSym.tnFncSym;
  3450.         xtraSym = thisArg->tnOp.tnOp2->tnFncSym.tnFncSym;
  3451.  
  3452.         thisArg = NULL;
  3453.     }
  3454.  
  3455.     assert(fncSym && fncSym->sdSymKind == SYM_FNC);
  3456.  
  3457. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3458.  
  3459.     SymDef          ovlFunc  = fncSym;
  3460.  
  3461.     if  (fncSym && !strcmp(fncSym->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3462.     {
  3463.         printf("\nOverloaded call [%08X]: begin\n", args);
  3464.         cmpParser->parseDispTree(args);
  3465.         printf("\n\n");
  3466.     }
  3467.  
  3468. #endif
  3469.  
  3470. AGAIN:
  3471.  
  3472.     for (;;)
  3473.     {
  3474.         SymDef          fncSave = fncSym;
  3475.         TypDef          baseCls;
  3476.  
  3477.         /* Walk the overload list, looking for the best match */
  3478.  
  3479.         do
  3480.         {
  3481.             TypDef          fncTyp;
  3482.             bool            extArgs;
  3483.  
  3484.             Tree            actuals;
  3485.             ArgDef          formals;
  3486.  
  3487.             int             argCost;
  3488.             int             maxCost;
  3489.             unsigned        totCost;
  3490.  
  3491.             unsigned        actCnt;
  3492.  
  3493.             /* Get hold of the type for the next overload */
  3494.  
  3495.             fncTyp = fncSym->sdType;
  3496.  
  3497.             /* Check the argument count, if it's been determined */
  3498.  
  3499.             if  (argCnt != fncTyp->tdFnc.tdfArgs.adCount &&
  3500.                  argCnt != -1)
  3501.             {
  3502.                 /* Do we have too few or too many arguments? */
  3503.  
  3504.                 if  (argCnt < fncTyp->tdFnc.tdfArgs.adCount)
  3505.                 {
  3506.                     /* We don't have enough arguments, there better be defaults */
  3507.  
  3508.                     if  (!fncTyp->tdFnc.tdfArgs.adDefs)
  3509.                         goto NEXT;
  3510.                 }
  3511.                 else
  3512.                 {
  3513.                     /* If it's a varargs function, too many args might be OK */
  3514.  
  3515.                     if  (!fncTyp->tdFnc.tdfArgs.adVarArgs)
  3516.                         goto NEXT;
  3517.                 }
  3518.             }
  3519.  
  3520. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3521.             if  (!strcmp(fncSym->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3522.                 printf("\nConsider '%s':\n", cmpGlobalST->stTypeName(fncTyp, fncSym, NULL, NULL, false));
  3523. #endif
  3524.  
  3525.             /* Does the function have extended argument descriptors? */
  3526.  
  3527.             extArgs = fncTyp->tdFnc.tdfArgs.adExtRec;
  3528.  
  3529.             /* Walk the formal and actual arguments, computing the max. cost */
  3530.  
  3531.             maxCost = 0;
  3532.             totCost = 0;
  3533.             actCnt  = 0;
  3534.  
  3535.             actuals = args;
  3536.             formals = fncTyp->tdFnc.tdfArgs.adArgs;
  3537.  
  3538.             /* Is there a "this" pointer? */
  3539.  
  3540.             if  (fncSym->sdIsMember && thisArg && !fncSym->sdIsStatic)
  3541.             {
  3542.                 TypDef          clsType = fncSym->sdParent->sdType;
  3543.  
  3544.                 assert(clsType->tdTypeKind == TYP_CLASS);
  3545.  
  3546.                 argCost = cmpConversionCost(thisArg, clsType->tdClass.tdcRefTyp);
  3547.                 if  (argCost < 0)
  3548.                     goto NEXT;
  3549.  
  3550. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3551.                 if  (!strcmp(ovlFunc->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3552.                 {
  3553.                     printf("'this' arg: cost = %d\n", argCost);
  3554.                     printf("    Formal: %s\n", cmpGlobalST->stTypeName(clsType->tdClass.tdcRefTyp, NULL, NULL, NULL, false));
  3555.                     printf("    Actual: %s\n", cmpGlobalST->stTypeName(thisArg->tnType           , NULL, NULL, NULL, false));
  3556.                 }
  3557. #endif
  3558.  
  3559.                 /* The "this" argument cost is our initial total/max cost */
  3560.  
  3561.                 maxCost = argCost;
  3562.                 totCost = argCost;
  3563.             }
  3564.  
  3565.             if  (actuals)
  3566.             {
  3567.                 do
  3568.                 {
  3569.                     Tree            actualx;
  3570.  
  3571.                     /* If there are no more formals, we have too many args */
  3572.  
  3573.                     if  (!formals)
  3574.                     {
  3575.                         /* If it's a varargs function, we have a match */
  3576.  
  3577.                         if  (fncTyp->tdFnc.tdfArgs.adVarArgs)
  3578.                             goto MATCH;
  3579.                         else
  3580.                             goto NEXT;
  3581.                     }
  3582.  
  3583.                     assert(actuals->tnOper == TN_LIST);
  3584.  
  3585.                     /* Count this argument */
  3586.  
  3587.                     actCnt++;
  3588.  
  3589.                     /* Get hold of the next actual value */
  3590.  
  3591.                     actualx = actuals->tnOp.tnOp1;
  3592.  
  3593.                     /* Is this supposed to be a byref argument? */
  3594.  
  3595.                     if  (extArgs)
  3596.                     {
  3597.                         /* The actual value has to be a matching lvalue */
  3598.  
  3599.                         assert(formals->adIsExt);
  3600.  
  3601.                         if  (((ArgExt)formals)->adFlags & (ARGF_MODE_OUT  |
  3602.                                                            ARGF_MODE_INOUT|
  3603.                                                            ARGF_MODE_REF))
  3604.                         {
  3605.                             /* The actual value has to be a matching lvalue */
  3606.  
  3607.                             if  (actualx->tnOper == TN_ADDROF)
  3608.                                 actualx = actualx->tnOp.tnOp1;
  3609.  
  3610.                             if  (cmpCheckLvalue(actualx, true, true) &&
  3611.                                  symTab::stMatchTypes(formals->adType, actualx->tnType))
  3612.                             {
  3613.                                 argCost =  0;
  3614.                             }
  3615.                             else
  3616.                                 argCost = -1;
  3617.  
  3618.                             goto GOT_ARGC;
  3619.                         }
  3620.                     }
  3621.  
  3622.                     /* Compute the conversion cost for this argument */
  3623.  
  3624.                     argCost = cmpConversionCost(actualx, formals->adType);
  3625.  
  3626.                 GOT_ARGC:
  3627.  
  3628. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3629.                     if  (!strcmp(ovlFunc->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3630.                     {
  3631.                         printf("Argument #%2u: cost = %d\n", actCnt, argCost);
  3632.                         printf("    Formal: %s\n", cmpGlobalST->stTypeName(formals->adType, NULL, NULL, NULL, false));
  3633.                         printf("    Actual: %s\n", cmpGlobalST->stTypeName(actualx->tnType, NULL, NULL, NULL, false));
  3634.                     }
  3635. #endif
  3636.  
  3637.                     /* If this value can't be converted at all, give up */
  3638.  
  3639.                     if  (argCost < 0)
  3640.                         goto NEXT;
  3641.  
  3642.                     /* Keep track of the total and highest cost */
  3643.  
  3644.                     totCost += argCost;
  3645.  
  3646.                     if  (maxCost < argCost)
  3647.                          maxCost = argCost;
  3648.  
  3649.                     /* Move on to the next formal */
  3650.  
  3651.                     formals = formals->adNext;
  3652.  
  3653.                     /* Are there any more actuals? */
  3654.  
  3655.                     actuals = actuals->tnOp.tnOp2;
  3656.                 }
  3657.                 while (actuals);
  3658.             }
  3659.  
  3660.             /* Remember how many actual args we've found for next round */
  3661.  
  3662.             argCnt = actCnt;
  3663.  
  3664.             /* This is a match if there are no more formals */
  3665.  
  3666.             if  (formals)
  3667.             {
  3668.                 /* Is there a default value? */
  3669.  
  3670.                 if  (!fncTyp->tdFnc.tdfArgs.adDefs || !extArgs)
  3671.                     goto NEXT;
  3672.  
  3673.                 /*
  3674.                     Note that we depend on the absence of gaps in trailing
  3675.                     argument defaults, i.e. once a default is specified all
  3676.                     the arguments that follow must also have defaults.
  3677.                  */
  3678.  
  3679.                 assert(formals->adIsExt);
  3680.  
  3681.                 if  (!(((ArgExt)formals)->adFlags & ARGF_DEFVAL))
  3682.                     goto NEXT;
  3683.             }
  3684.  
  3685.         MATCH:
  3686.  
  3687. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3688.             if  (!strcmp(ovlFunc->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3689.                 printf("\nMax. cost = %2u, total cost = %u\n", maxCost, totCost);
  3690. #endif
  3691.  
  3692.             /* Compare the max. cost to the best so far */
  3693.  
  3694.             if  (maxCost > bestCost)
  3695.                 goto NEXT;
  3696.  
  3697.             /* Is this a clearly better match? */
  3698.  
  3699.             if  (maxCost < bestCost || totCost < btotCost)
  3700.             {
  3701.                 bestCost = maxCost;
  3702.                 btotCost = totCost;
  3703.                 bestSym  = fncSym;
  3704.                 bestTyp  = fncTyp;
  3705.                 moreSym  = NULL;
  3706.  
  3707.                 goto NEXT;
  3708.             }
  3709.  
  3710.             if  (totCost == btotCost)
  3711.             {
  3712.                 /*
  3713.                     This function is exactly as good as the best match we've
  3714.                     found so far. In fact, it will be hidden by our best match
  3715.                     if we're in a base class. If the argument lists match, we
  3716.                     ignore this function and move on.
  3717.                  */
  3718.  
  3719.                 if  (!inBase || !cmpGlobalST->stArgsMatch(bestTyp, fncTyp))
  3720.                     moreSym = fncSym;
  3721.             }
  3722.  
  3723.         NEXT:
  3724.  
  3725.             /* Continue with the next overload, if any */
  3726.  
  3727.             fncSym = fncSym->sdFnc.sdfNextOvl;
  3728.         }
  3729.         while (fncSym);
  3730.  
  3731.         /* Do we have base class overloads? */
  3732.  
  3733.         if  (!fncSave->sdFnc.sdfBaseOvl)
  3734.             break;
  3735.  
  3736.         /* Look for a method with the same name in the base class */
  3737.  
  3738.         assert(fncSave->sdParent->sdSymKind == SYM_CLASS);
  3739.  
  3740.         baseCls = fncSave->sdParent->sdType->tdClass.tdcBase;
  3741.         if  (!baseCls)
  3742.             break;
  3743.  
  3744.         assert(baseCls->tdTypeKind == TYP_CLASS);
  3745.  
  3746.         fncSym = cmpGlobalST->stLookupAllCls(fncSave->sdName,
  3747.                                              baseCls->tdClass.tdcSymbol,
  3748.                                              NS_NORM,
  3749.                                              CS_DECLSOON);
  3750.  
  3751.         if  (!fncSym || fncSym->sdSymKind != SYM_FNC)
  3752.             break;
  3753.  
  3754.         /* We'll have to weed out hidden methods in the base */
  3755.  
  3756.         inBase = true;
  3757.     }
  3758.  
  3759.     /* Do we have another set of functions to consider? */
  3760.  
  3761.     if  (xtraSym)
  3762.     {
  3763.         fncSym = xtraSym;
  3764.                  xtraSym = NULL;
  3765.  
  3766.         goto AGAIN;
  3767.     }
  3768.  
  3769. #ifdef  SHOW_OVRS_OF_THIS_FNC
  3770.     if  (!strcmp(ovlFunc->sdSpelling(), SHOW_OVRS_OF_THIS_FNC) || !strcmp(SHOW_OVRS_OF_THIS_FNC, "*"))
  3771.         printf("\nOverloaded call [%08X]: done.\n\n", args);
  3772. #endif
  3773.  
  3774.     /* Is the call ambiguous? */
  3775.  
  3776.     if  (moreSym)
  3777.     {
  3778.         /* Report an ambiguity error */
  3779.  
  3780.         cmpErrorQSS(ERRambigCall, bestSym, moreSym);
  3781.     }
  3782.  
  3783.     return  bestSym;
  3784. }
  3785.  
  3786. /*****************************************************************************
  3787.  *
  3788.  *  Given a function call node with a bound function member and argument list,
  3789.  *  check the arguments and return an expression that represents the result of
  3790.  *  calling the function.
  3791.  */
  3792.  
  3793. Tree                compiler::cmpCheckFuncCall(Tree call)
  3794. {
  3795.     SymDef          fncSym;
  3796.     TypDef          fncTyp;
  3797.     SymDef          ovlSym = NULL;
  3798.     Tree            fncLst = NULL;
  3799.  
  3800.     ArgDef          formal;
  3801.     Tree            actual;
  3802.     Tree            actLst;
  3803.     Tree            actNul = NULL;
  3804.     Tree            defExp;
  3805.     unsigned        argCnt;
  3806.     unsigned        argNum;
  3807.     bool            extArg;
  3808.  
  3809.     switch (call->tnOper)
  3810.     {
  3811.     case TN_FNC_SYM:
  3812.  
  3813.         /* Get the arguments from the call node */
  3814.  
  3815.         actual = call->tnFncSym.tnFncArgs;
  3816.  
  3817.     CHK_OVL:
  3818.  
  3819.         fncSym = call->tnFncSym.tnFncSym;
  3820.         assert(fncSym->sdSymKind == SYM_FNC);
  3821.  
  3822.         /* Is the method overloaded? */
  3823.  
  3824.         if  (fncSym->sdFnc.sdfNextOvl || fncSym->sdFnc.sdfBaseOvl)
  3825.         {
  3826.             /* Try to find a matching overload */
  3827.  
  3828.             ovlSym = cmpFindOvlMatch(fncSym, call->tnFncSym.tnFncArgs,
  3829.                                              call->tnFncSym.tnFncObj);
  3830.  
  3831.             /* Bail if no matching function was found */
  3832.  
  3833.             if  (!ovlSym)
  3834.             {
  3835.  
  3836.             ERR:
  3837.  
  3838.                 if  (!cmpExprIsErr(call->tnFncSym.tnFncArgs))
  3839.                 {
  3840.                     if  (fncSym->sdFnc.sdfCtor)
  3841.                     {
  3842.                         SymDef          parent = fncSym->sdParent;
  3843.  
  3844.                         if  (parent && parent->sdSymKind         == SYM_CLASS
  3845.                                     && parent->sdClass.sdcFlavor == STF_DELEGATE)
  3846.                         {
  3847.                             Tree            args = call->tnFncSym.tnFncArgs;
  3848.  
  3849.                             assert(call->tnOper == TN_FNC_SYM);
  3850.                             assert(args->tnOper == TN_LIST);
  3851.                             args = args->tnOp.tnOp2;
  3852.                             assert(args->tnOper == TN_LIST);
  3853.                             args = args->tnOp.tnOp1;
  3854.                             assert(args->tnOper == TN_ADDROF);
  3855.                             args = args->tnOp.tnOp1;
  3856.                             assert(args->tnOper == TN_FNC_PTR);
  3857.  
  3858.                             cmpErrorQSS(ERRnoDlgMatch, args->tnFncSym.tnFncSym, parent);
  3859.                         }
  3860.                         else
  3861.                         {
  3862.                             cmpErrorXtp(ERRnoCtorMatch, parent, call->tnFncSym.tnFncArgs);
  3863.                         }
  3864.                     }
  3865.                     else
  3866.                     {
  3867.                         SymDef          clsSym;
  3868.  
  3869.                         cmpErrorXtp(ERRnoOvlMatch, fncSym, call->tnFncSym.tnFncArgs);
  3870.  
  3871.                         clsSym = fncSym->sdParent; assert(clsSym);
  3872.  
  3873.                         if  (clsSym->sdSymKind == SYM_CLASS)
  3874.                         {
  3875.                             SymDef          baseMFN;
  3876.  
  3877.                             if  (clsSym->sdType->tdClass.tdcBase == NULL)
  3878.                                 break;
  3879.  
  3880.                             clsSym  = clsSym->sdType->tdClass.tdcBase->tdClass.tdcSymbol;
  3881.                             baseMFN = cmpGlobalST->stLookupClsSym(fncSym->sdName, clsSym);
  3882.  
  3883.                             if  (baseMFN)
  3884.                             {
  3885.                                 ovlSym = cmpFindOvlMatch(baseMFN, call->tnFncSym.tnFncArgs,
  3886.                                                                   call->tnFncSym.tnFncObj);
  3887.                                 if  (ovlSym)
  3888.                                 {
  3889.                                     cmpErrorQnm(ERRhideMatch, ovlSym);
  3890.                                     goto RET_ERR;
  3891.                                 }
  3892.                             }
  3893.                         }
  3894.                     }
  3895.                 }
  3896.  
  3897.             RET_ERR:
  3898.  
  3899.                 return cmpCreateErrNode();
  3900.             }
  3901.  
  3902.         MFN:
  3903.  
  3904.             call->tnFncSym.tnFncSym = fncSym = ovlSym;
  3905.         }
  3906.  
  3907.         fncTyp = fncSym->sdType; assert(fncTyp->tdTypeKind == TYP_FNC);
  3908.  
  3909.         /* Make sure we are allowed to access the function */
  3910.  
  3911.         cmpCheckAccess(fncSym);
  3912.  
  3913.         /* Has the function been marked as "deprecated" ? */
  3914.  
  3915.         if  (fncSym->sdIsDeprecated || (fncSym->sdParent && fncSym->sdParent->sdIsDeprecated))
  3916.         {
  3917.             if  (fncSym->sdIsImport)
  3918.             {
  3919.                 if  (fncSym->sdIsDeprecated)
  3920.                     cmpObsoleteUse(fncSym          , WRNdepCall);
  3921.                 else
  3922.                     cmpObsoleteUse(fncSym->sdParent, WRNdepCls);
  3923.             }
  3924.         }
  3925.  
  3926.         break;
  3927.  
  3928.     case TN_CALL:
  3929.  
  3930.         assert(call->tnOp.tnOp1->tnOper == TN_IND);
  3931.  
  3932. #ifdef  DEBUG
  3933.         fncSym = NULL;
  3934. #endif
  3935.         fncTyp = call->tnOp.tnOp1->tnType;
  3936.  
  3937.         /* Get the arguments from the call node */
  3938.  
  3939.         actual = call->tnOp.tnOp2;
  3940.         break;
  3941.  
  3942.     case TN_LIST:
  3943.  
  3944.         /* The function list is in op1, the arguments are in op2 */
  3945.  
  3946.         actual = call->tnOp.tnOp2;
  3947.         fncLst = call->tnOp.tnOp1;
  3948.  
  3949.         if  (fncLst->tnOper == TN_LIST)
  3950.         {
  3951.             /* We have more than one set of candidate functions */
  3952.  
  3953.             assert(fncLst->tnOp.tnOp1->tnOper == TN_FNC_SYM);
  3954.             assert(fncLst->tnOp.tnOp2->tnOper == TN_FNC_SYM);
  3955.  
  3956.             /* Look for a matching overload */
  3957.  
  3958.             ovlSym = cmpFindOvlMatch(NULL, actual, fncLst);
  3959.  
  3960.             if  (!ovlSym)
  3961.                 goto ERR;
  3962.  
  3963.             call->tnOper             = TN_FNC_SYM;
  3964.             call->tnFncSym.tnFncArgs = actual;
  3965.  
  3966.             goto MFN;
  3967.         }
  3968.         else
  3969.         {
  3970.             /* There is one candidate set of functions */
  3971.  
  3972.             call = fncLst; assert(call->tnOper == TN_FNC_SYM);
  3973.  
  3974.             goto CHK_OVL;
  3975.         }
  3976.         break;
  3977.  
  3978.     default:
  3979.         NO_WAY(!"weird call");
  3980.     }
  3981.  
  3982.     assert(fncTyp->tdTypeKind == TYP_FNC);
  3983.  
  3984.     /* Walk the argument list, checking each type as we go */
  3985.  
  3986.     formal = fncTyp->tdFnc.tdfArgs.adArgs;
  3987.     extArg = fncTyp->tdFnc.tdfArgs.adExtRec;
  3988.     defExp =
  3989.     actLst = NULL;
  3990.     argCnt = 0;
  3991.  
  3992.     for (argNum = 0; ; argNum++)
  3993.     {
  3994.         Tree            actExp;
  3995.         TypDef          formTyp;
  3996.  
  3997.         /* Are there any actual arguments left? */
  3998.  
  3999.         if  (actual == NULL)
  4000.         {
  4001.             /* No more actuals -- there better be no more formals */
  4002.  
  4003.             if  (formal)
  4004.             {
  4005.                 /* Is there a default value? */
  4006.  
  4007.                 if  (extArg)
  4008.                 {
  4009.                     ArgExt          formExt = (ArgExt)formal;
  4010.  
  4011.                     assert(formal->adIsExt);
  4012.  
  4013.                     /* Grab a default value if it's present */
  4014.  
  4015.                     if  (formExt->adFlags & ARGF_DEFVAL)
  4016.                     {
  4017. #if MGDDATA
  4018.                         actExp = cmpFetchConstVal( formExt->adDefVal);
  4019. #else
  4020.                         actExp = cmpFetchConstVal(&formExt->adDefVal);
  4021. #endif
  4022.                         defExp = cmpCreateExprNode(NULL,
  4023.                                                    TN_LIST,
  4024.                                                    cmpTypeVoid,
  4025.                                                    actExp,
  4026.                                                    NULL);
  4027.  
  4028.                         /* Add the argument to the actual argument list */
  4029.  
  4030.                         if  (actLst)
  4031.                         {
  4032.                             assert(actLst->tnOper     == TN_LIST);
  4033.                             assert(actLst->tnOp.tnOp2 == NULL);
  4034.  
  4035.                             actLst->tnOp.tnOp2       = defExp;
  4036.                         }
  4037.                         else
  4038.                         {
  4039.                             call->tnFncSym.tnFncArgs = defExp;
  4040.                         }
  4041.  
  4042.                         actLst = defExp;
  4043.  
  4044.                         goto CHKARG;
  4045.                     }
  4046.                 }
  4047.  
  4048.                 if  (fncSym->sdFnc.sdfCtor)
  4049.                     goto ERR;
  4050.  
  4051.                 cmpErrorQnm(ERRmisgArg, fncSym);
  4052.                 return cmpCreateErrNode();
  4053.             }
  4054.  
  4055.             /* No more actuals or formals -- looks like we're done! */
  4056.  
  4057.             break;
  4058.         }
  4059.  
  4060.         /* Count this argument, in case we have to give an error */
  4061.  
  4062.         argCnt++;
  4063.  
  4064.         /* Get hold of the next argument value */
  4065.  
  4066.         assert(actual->tnOper == TN_LIST);
  4067.         actExp = actual->tnOp.tnOp1;
  4068.  
  4069.     CHKARG:
  4070.  
  4071.         /* Are there any formal parameters left? */
  4072.  
  4073.         if  (formal == NULL)
  4074.         {
  4075.             var_types       actVtp;
  4076.  
  4077.             /* Is this a varargs function? */
  4078.  
  4079.             if  (!fncTyp->tdFnc.tdfArgs.adVarArgs)
  4080.             {
  4081.                 /* Check for "va_start" and "va_arg" */
  4082.  
  4083.                 if  (fncSym == cmpFNsymVAbeg ||
  4084.                      fncSym == cmpFNsymVAget)
  4085.                 {
  4086.                     return  cmpBindVarArgUse(call);
  4087.                 }
  4088.  
  4089.                 /* Too many actual arguments */
  4090.  
  4091.                 if  (fncSym->sdFnc.sdfCtor)
  4092.                     goto ERR;
  4093.  
  4094.                 cmpErrorQnm(ERRmanyArg, fncSym);
  4095.                 return cmpCreateErrNode();
  4096.             }
  4097.  
  4098.             /* Mark the call as "varargs" */
  4099.  
  4100.             call->tnFlags |= TNF_CALL_VARARG;
  4101.  
  4102.             /* Promote the argument if small int or FP value */
  4103.  
  4104.             actVtp = actExp->tnVtypGet();
  4105.  
  4106.             if  (varTypeIsArithmetic(actVtp))
  4107.             {
  4108.                 if      (actVtp == TYP_FLOAT)
  4109.                 {
  4110.                     /* Promote float varargs values to double */
  4111.  
  4112.                     actVtp = TYP_DOUBLE;
  4113.                 }
  4114.                 else if (actVtp >= TYP_CHAR && actVtp < TYP_INT)
  4115.                 {
  4116.                     actVtp = TYP_INT;
  4117.                 }
  4118.                 else
  4119.                     goto NEXT_ARG;
  4120.  
  4121.                 formTyp = cmpGlobalST->stIntrinsicType(actVtp);
  4122.  
  4123.                 goto CAST_ARG;
  4124.             }
  4125.  
  4126.             goto NEXT_ARG;
  4127.         }
  4128.  
  4129.         /* Get the type of the formal parameter */
  4130.  
  4131.         formTyp = cmpDirectType(formal->adType);
  4132.  
  4133.         /* Get the argument flags, if present */
  4134.  
  4135.         if  (extArg)
  4136.         {
  4137.             unsigned        argFlags;
  4138.  
  4139.             assert(formal->adIsExt);
  4140.  
  4141.             argFlags = ((ArgExt)formal)->adFlags;
  4142.  
  4143.             if  (argFlags & (ARGF_MODE_OUT|ARGF_MODE_INOUT|ARGF_MODE_REF))
  4144.             {
  4145.                 Tree            argx;
  4146.  
  4147.                 /* We must have an lvalue of the exact right type */
  4148.  
  4149.                 if  (actExp->tnOper == TN_ADDROF)
  4150.                 {
  4151.                     actExp = actExp->tnOp.tnOp1;
  4152.                 }
  4153.                 else
  4154.                 {
  4155.                     if  (argFlags & (ARGF_MODE_INOUT|ARGF_MODE_OUT))
  4156.                         cmpWarnNqn(WRNimplOut, argNum+1, fncSym);
  4157.                 }
  4158.  
  4159.                 if  (!cmpCheckLvalue(actExp, true))
  4160.                     return cmpCreateErrNode();
  4161.  
  4162.                 if  (!symTab::stMatchTypes(formTyp, actExp->tnType))
  4163.                     goto ARG_ERR;
  4164.  
  4165.                 // UNDONE: Make sure the lvalue is GC/non-GC as appropriate
  4166.  
  4167.                 argx = cmpCreateExprNode(NULL,
  4168.                                          TN_ADDROF,
  4169.                                          cmpGlobalST->stNewRefType(TYP_PTR, formTyp),
  4170.                                          actExp,
  4171.                                          NULL);
  4172.  
  4173.                 argx->tnFlags |= TNF_ADR_OUTARG;
  4174.  
  4175.                 /* Store the updated value in the arglist and continue */
  4176.  
  4177.                 actual->tnOp.tnOp1 = argx;
  4178.                 goto NEXT_ARG;
  4179.             }
  4180.         }
  4181.  
  4182.         /* If we haven't performed overload resolution ... */
  4183.  
  4184.         if  (!ovlSym)
  4185.         {
  4186.             /* Make sure the argument can be converted */
  4187.  
  4188.             if  (cmpConversionCost(actExp, formTyp) < 0)
  4189.             {
  4190.                 char            temp[16];
  4191.                 int             errn;
  4192.                 stringBuff      nstr;
  4193.  
  4194.             ARG_ERR:
  4195.  
  4196.                 /* Issue an error and give up on this argument */
  4197.  
  4198.                 if  (formal->adName)
  4199.                 {
  4200.                     nstr = formal->adName->idSpelling();
  4201.                     errn = ERRbadArgValNam;
  4202.                 }
  4203.                 else
  4204.                 {
  4205.                     sprintf(temp, "%u", argCnt);
  4206.                     nstr = makeStrBuff(temp);
  4207.                     errn = ERRbadArgValNum;
  4208.                 }
  4209.  
  4210.                 cmpErrorSST(errn, nstr, fncSym, actExp->tnType);
  4211.                 goto NEXT_ARG;
  4212.             }
  4213.         }
  4214.  
  4215.         /* Coerce the argument to the formal argument's type */
  4216.  
  4217.         if  (actExp->tnType != formTyp)
  4218.         {
  4219.             Tree            conv;
  4220.  
  4221.         CAST_ARG:
  4222.  
  4223.             conv = cmpCoerceExpr(actExp, formTyp, false);
  4224.  
  4225.             if  (actual)
  4226.                 actual->tnOp.tnOp1 = conv;
  4227.             else
  4228.                 defExp->tnOp.tnOp1 = conv;
  4229.         }
  4230.  
  4231.     NEXT_ARG:
  4232.  
  4233.         /* Move to the next formal and actual argument */
  4234.  
  4235.         if  (formal)
  4236.             formal = formal->adNext;
  4237.  
  4238.         if  (actual)
  4239.         {
  4240.             actLst = actual;
  4241.             actual = actual->tnOp.tnOp2;
  4242.         }
  4243.     }
  4244.  
  4245.     /* Get hold of the return type and set the type of the call */
  4246.  
  4247.     call->tnType = cmpDirectType(fncTyp->tdFnc.tdfRett);
  4248.     call->tnVtyp = call->tnType->tdTypeKind;
  4249.  
  4250.     return call;
  4251. }
  4252.  
  4253. /*****************************************************************************
  4254.  *
  4255.  *  Bind a call to a function.
  4256.  */
  4257.  
  4258. Tree                compiler::cmpBindCall(Tree expr)
  4259. {
  4260.     Tree            func;
  4261.  
  4262.     Tree            fncx;
  4263.     Tree            args;
  4264.  
  4265.     SymDef          fsym;
  4266.     TypDef          ftyp;
  4267.  
  4268.     bool            indir;
  4269.  
  4270.     SymDef          errSym = NULL;
  4271.     bool            CTcall = false;
  4272.  
  4273.     assert(expr->tnOper == TN_CALL);
  4274.  
  4275.     /* The expression being called must be an optionally dotted name */
  4276.  
  4277.     func = expr->tnOp.tnOp1;
  4278.  
  4279.     switch (func->tnOper)
  4280.     {
  4281.     case TN_NAME:
  4282.     case TN_ANY_SYM:
  4283.         fncx = cmpBindNameUse(func, true, false);
  4284.         break;
  4285.  
  4286.     case TN_DOT:
  4287.     case TN_ARROW:
  4288.         fncx = cmpBindDotArr(func, true, false);
  4289.         if  (fncx->tnOper == TN_ARR_LEN)
  4290.             return  fncx;
  4291.         break;
  4292.  
  4293.     case TN_THIS:
  4294.     case TN_BASE:
  4295.  
  4296.         /* Make sure we are in a constructor */
  4297.  
  4298.         if  (!cmpCurFncSym || !cmpCurFncSym->sdFnc.sdfCtor)
  4299.         {
  4300.             cmpError(ERRbadCall);
  4301.             return cmpCreateErrNode();
  4302.         }
  4303.  
  4304.         /* Figure out which class to look for the constructor in */
  4305.  
  4306.         ftyp = cmpCurCls->sdType;
  4307.  
  4308.         if  (func->tnOper == TN_BASE)
  4309.         {
  4310.             if  (ftyp->tdClass.tdcValueType && ftyp->tdIsManaged)
  4311.             {
  4312.                 /* Managed structs don't really have a base class */
  4313.  
  4314.                 ftyp = NULL;
  4315.             }
  4316.             else
  4317.                 ftyp = ftyp->tdClass.tdcBase;
  4318.  
  4319.             /* Make sure this is actually OK */
  4320.  
  4321.             if  (!cmpBaseCTisOK || ftyp == NULL)
  4322.                 cmpError(ERRbadBaseCall);
  4323.  
  4324.             /* This can only be done once, of course */
  4325.  
  4326.             cmpBaseCTisOK = false;
  4327.  
  4328.             /* We should have noticed that "baseclass()" is called */
  4329.  
  4330.             assert(cmpBaseCTcall == false);
  4331.         }
  4332.  
  4333.         /* Get the constructor symbol from the class */
  4334.  
  4335.         fsym = cmpFindCtor(ftyp, false);
  4336.         if  (!fsym)
  4337.         {
  4338.             /* Must have had some nasty errors earlier */
  4339.  
  4340.             assert(cmpErrorCount);
  4341.             return cmpCreateErrNode();
  4342.         }
  4343.  
  4344.         /* Create the member function call node */
  4345.  
  4346.         fncx = cmpCreateExprNode(NULL, TN_FNC_SYM, fsym->sdType);
  4347.  
  4348.         fncx->tnFncSym.tnFncObj = cmpThisRef();
  4349.         fncx->tnFncSym.tnFncSym = fsym;
  4350.         fncx->tnFncSym.tnFncScp  = NULL;
  4351.  
  4352.         break;
  4353.  
  4354.     case TN_ERROR:
  4355.         return  func;
  4356.  
  4357.     default:
  4358.         return cmpCreateErrNode(ERRbadCall);
  4359.     }
  4360.  
  4361.     /* If we got an error binding the function, bail */
  4362.  
  4363.     if  (fncx->tnVtyp == TYP_UNDEF)
  4364.         return fncx;
  4365.  
  4366.     /* At this point we expect to have a function */
  4367.  
  4368.     if  (fncx->tnVtyp != TYP_FNC)
  4369.         return cmpCreateErrNode(ERRbadCall);
  4370.  
  4371.     ftyp = fncx->tnType;
  4372.     assert(ftyp->tdTypeKind == TYP_FNC);
  4373.  
  4374.     /* Bind the argument list */
  4375.  
  4376.     args = NULL;
  4377.  
  4378.     if  (expr->tnOp.tnOp2)
  4379.     {
  4380.         args = expr->tnOp.tnOp2; assert(args->tnOper == TN_LIST);
  4381.  
  4382.         /* Special case: the second operand of va_arg() must be a type */
  4383.  
  4384.         if  (fncx->tnOper == TN_FNC_SYM && fncx->tnFncSym.tnFncSym == cmpFNsymVAget)
  4385.         {
  4386.             /* Bind both arguments (allow the second one to be a type) */
  4387.  
  4388.             args->tnOp.tnOp1 = cmpBindExprRec(args->tnOp.tnOp1);
  4389.  
  4390.             if  (args->tnOp.tnOp2)
  4391.             {
  4392.                 Tree            arg2 = args->tnOp.tnOp2->tnOp.tnOp1;
  4393.  
  4394.                 /* All error checking is done elsewhere, just check for type */
  4395.  
  4396.                 if  (arg2->tnOper == TN_TYPE)
  4397.                 {
  4398.                     arg2->tnType = cmpActualType(arg2->tnType);
  4399.                     arg2->tnVtyp = arg2->tnType->tdTypeKindGet();
  4400.                 }
  4401.                 else
  4402.                 {
  4403.                     args->tnOp.tnOp2->tnOp.tnOp1 = cmpBindExprRec(arg2);
  4404.                 }
  4405.             }
  4406.         }
  4407.         else
  4408.         {
  4409.             args = cmpBindExprRec(args);
  4410.  
  4411.             if  (args->tnVtyp == TYP_UNDEF)
  4412.                 return args;
  4413.         }
  4414.     }
  4415.  
  4416.     /* Is this a direct or indirect function call ? */
  4417.  
  4418.     if  (fncx->tnOper == TN_FNC_SYM)
  4419.     {
  4420.         /* Direct call to a function symbol */
  4421.  
  4422.         fsym  = fncx->tnFncSym.tnFncSym; assert(fsym->sdSymKind == SYM_FNC);
  4423.         indir = false;
  4424.  
  4425.         /* Store the arguments in the call node */
  4426.  
  4427.         fncx->tnFncSym.tnFncArgs = args;
  4428.     }
  4429.     else
  4430.     {
  4431.         /* Must be an indirect call through a function pointer */
  4432.  
  4433.         assert(fncx->tnOper == TN_IND);
  4434.  
  4435.         fsym  = NULL;
  4436.         indir = true;
  4437.         fncx  = cmpCreateExprNode(NULL, TN_CALL, cmpTypeInt, fncx, args);
  4438.     }
  4439.  
  4440. #if 0
  4441.     printf("Func:\n");
  4442.     cmpParser->parseDispTree(fncx);
  4443.     printf("Args:\n");
  4444.     cmpParser->parseDispTree(args);
  4445.     printf("\n");
  4446. #endif
  4447.  
  4448.     /* In case something goes wrong ... */
  4449.  
  4450.     cmpRecErrorPos(expr);
  4451.  
  4452.     /* Check the call (performing overload resolution of necessary) */
  4453.  
  4454.     fncx = cmpCheckFuncCall(fncx);
  4455.     if  (fncx->tnVtyp == TYP_UNDEF)
  4456.         return  fncx;
  4457.  
  4458.     /* Typedefs should be folded by now */
  4459.  
  4460.     assert(fncx->tnVtyp != TYP_TYPEDEF);
  4461.  
  4462.     /* Was this a direct or indirect call? */
  4463.  
  4464.     if  (indir)
  4465.         return  fncx;
  4466.  
  4467.     if  (fncx->tnOper != TN_FNC_SYM)
  4468.     {
  4469.         assert(fncx->tnOper == TN_VARARG_BEG ||
  4470.                fncx->tnOper == TN_VARARG_GET);
  4471.  
  4472.         return  fncx;
  4473.     }
  4474.  
  4475.     /* Get the function symbol the call resolved to */
  4476.  
  4477.     fsym = fncx->tnFncSym.tnFncSym;
  4478.  
  4479.     /*
  4480.         If the function is private or it's a method of a final
  4481.         class, the call to it won't need to be virtual.
  4482.      */
  4483.  
  4484.     if  (fsym->sdIsMember)
  4485.     {
  4486.         if  (fsym->sdAccessLevel == ACL_PRIVATE)
  4487.             fncx->tnFlags |= TNF_CALL_NVIRT;
  4488.         if  (fsym->sdParent->sdIsSealed)
  4489.             fncx->tnFlags |= TNF_CALL_NVIRT;
  4490.     }
  4491.  
  4492.     /* Did we have an object or just a class name reference? */
  4493.  
  4494.     if  (fncx->tnFncSym.tnFncObj)
  4495.     {
  4496.         Tree            objExpr = fncx->tnFncSym.tnFncObj;
  4497.  
  4498.         /* Special case: "base.func()" is *not* virtual */
  4499.  
  4500.         if  ((objExpr->tnOper == TN_LCL_SYM   ) &&
  4501.              (objExpr->tnFlags & TNF_LCL_BASE))
  4502.         {
  4503.             fncx->tnFlags |= TNF_CALL_NVIRT;
  4504.         }
  4505.     }
  4506.     else
  4507.     {
  4508.         SymDef          memSym = fncx->tnFncSym.tnFncSym;
  4509.  
  4510.         /* Are we calling a member function ? */
  4511.  
  4512.         if  (memSym->sdIsMember)
  4513.         {
  4514.             /* The called member must belong to our class or be static */
  4515.  
  4516.             if  (!memSym->sdIsStatic)
  4517.             {
  4518.                 SymDef          memCls;
  4519.  
  4520.                 /* Figure out the scope the member came from */
  4521.  
  4522.                 memCls = fncx->tnFncSym.tnFncScp;
  4523.                 if  (!memCls)
  4524.                     memCls = memSym->sdParent;
  4525.  
  4526.                 /* Does the member belong to a base? */
  4527.  
  4528.                 if  (cmpCurCls  &&
  4529.                      cmpThisSym && cmpIsBaseClass(memCls->sdType, cmpCurCls->sdType))
  4530.                 {
  4531.                     /* Stick an implicit "this->" in front of the reference */
  4532.  
  4533.                     fncx->tnFncSym.tnFncObj = cmpThisRefOK();
  4534.                 }
  4535.                 else
  4536.                 {
  4537.                     SymDef          parent;
  4538.  
  4539.                     // The following is a truly outrageous hack. I'm proud of it, though.
  4540.  
  4541.                     parent = memSym->sdParent;
  4542.                              memSym->sdParent = memCls;
  4543.                     cmpErrorQnm(ERRmemWOthis, memSym);
  4544.                              memSym->sdParent = parent;
  4545.  
  4546.                     return cmpCreateErrNode();
  4547.                 }
  4548.             }
  4549.         }
  4550.         else
  4551.         {
  4552.             /* Check for a few "well-known" functions */
  4553.  
  4554.             if  ((hashTab::getIdentFlags(memSym->sdName) & IDF_PREDEF) &&
  4555.                  memSym->sdIsDefined == false &&
  4556.                  memSym->sdParent == cmpGlobalNS)
  4557.             {
  4558.                 if      (memSym->sdName == cmpIdentDbgBreak)
  4559.                 {
  4560.                     assert(args == NULL);
  4561.  
  4562.                     fncx = cmpCreateExprNode(fncx, TN_DBGBRK, cmpTypeVoid);
  4563.  
  4564.                     memSym->sdIsImplicit = true;
  4565.                 }
  4566.                 else if (memSym->sdName == cmpIdentXcptCode)
  4567.                 {
  4568.                     Ident           getxName;
  4569.                     SymDef          getxSym;
  4570.                     SymDef          getxCls;
  4571.  
  4572.                     Tree            xvar;
  4573.  
  4574.                     assert(args == NULL);
  4575.  
  4576.                     memSym->sdIsImplicit = true;
  4577.  
  4578.                     /* This is only allowed within a filter expression */
  4579.  
  4580.                     if  (!cmpFilterObj)
  4581.                     {
  4582.                         cmpError(ERRnotFlx, memSym);
  4583.                         return cmpCreateErrNode();
  4584.                     }
  4585.  
  4586.                     /* Use "System::Interop::Marshal::GetExceptionCode(except_obj)" */
  4587.  
  4588.                     xvar = cmpCreateExprNode(NULL, TN_LCL_SYM, cmpExceptRef());
  4589.                     xvar->tnLclSym.tnLclSym  = cmpFilterObj;
  4590.  
  4591.                     /* Find the "System::Interop::Marshal" class */
  4592.  
  4593.                     getxCls = cmpMarshalCls;
  4594.                     if  (!getxCls)
  4595.                     {
  4596.                         // System::Interop::Marshal
  4597.  
  4598.                         getxCls = cmpGlobalST->stLookupNspSym(cmpGlobalHT->hashString("Marshal"),
  4599.                                                               NS_NORM,
  4600.                                                               cmpInteropGet());
  4601.  
  4602.                         if  (!getxCls || getxCls->sdSymKind != SYM_CLASS)
  4603.                             cmpGenFatal(ERRbltinTp, "System::Interop::Marshal");
  4604.  
  4605.                         cmpMarshalCls = getxCls;
  4606.                     }
  4607.  
  4608.                     /* Find "GetExceptionCode()" and create the call */
  4609.  
  4610.                     getxName = cmpGlobalHT->hashString("GetExceptionCode");
  4611.                     getxSym  = cmpGlobalST->stLookupClsSym(getxName, getxCls);
  4612.  
  4613.                     /* Make sure we find exactly one matching method */
  4614.  
  4615.                     assert(getxSym && getxSym->sdIsStatic
  4616.                                    && getxSym->sdFnc.sdfNextOvl == NULL);
  4617.  
  4618.                     fncx->tnOper             = TN_FNC_SYM;
  4619.                     fncx->tnFncSym.tnFncSym  = getxSym;
  4620.                     fncx->tnFncSym.tnFncArgs = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, xvar, NULL);
  4621.                     fncx->tnFncSym.tnFncObj  = NULL;
  4622.                     fncx->tnFncSym.tnFncScp  = NULL;
  4623.                 }
  4624.                 else if (memSym->sdName == cmpIdentXcptInfo)
  4625.                 {
  4626.                     UNIMPL("sorry, can't use _exception_info for now");
  4627.                 }
  4628.             }
  4629.         }
  4630.     }
  4631.  
  4632.     return fncx;
  4633. }
  4634.  
  4635. /*****************************************************************************
  4636.  *
  4637.  *  Bind an assignment.
  4638.  */
  4639.  
  4640. Tree                compiler::cmpBindAssignment(Tree          dstx,
  4641.                                                 Tree          srcx,
  4642.                                                 Tree          expr,
  4643.                                                 treeOps       oper)
  4644. {
  4645.     TypDef          dstType;
  4646.     var_types       dstVtyp;
  4647.  
  4648.     /* Mark the target of the assignment */
  4649.  
  4650.     dstx->tnFlags |= TNF_ASG_DEST;
  4651.  
  4652.     /* In case the coercion or lvalue check fail ... */
  4653.  
  4654.     cmpRecErrorPos(expr);
  4655.  
  4656.     /* Usually the result has the same type as the target */
  4657.  
  4658.     dstType = dstx->tnType;
  4659.     dstVtyp = dstType->tdTypeKindGet();
  4660.  
  4661.     /* Check for an assignment to an indexed property */
  4662.  
  4663.     if  (dstVtyp == TYP_FNC && dstx->tnOper == TN_PROPERTY)
  4664.     {
  4665.         Tree            dest = dstx->tnVarSym.tnVarObj;
  4666.  
  4667.         assert(dest && dest->tnOper == TN_LIST);
  4668.         assert(oper == TN_ASG && "sorry, things like += are not allowed with properties for now");
  4669.  
  4670.         dstx->tnVarSym.tnVarObj = dest->tnOp.tnOp1;
  4671.  
  4672.         return  cmpBindProperty(dstx, dest->tnOp.tnOp2, srcx);
  4673.     }
  4674.  
  4675.     /* Check for an overloaded operator */
  4676.  
  4677.     if  (dstVtyp == TYP_CLASS || dstVtyp == TYP_REF && oper != TN_ASG)
  4678.     {
  4679.         Tree            ovlx;
  4680.  
  4681.         expr->tnOp.tnOp1 = dstx;
  4682.         expr->tnOp.tnOp2 = srcx;
  4683.  
  4684.         ovlx = cmpCheckOvlOper(expr);
  4685.         if  (ovlx)
  4686.             return  ovlx;
  4687.     }
  4688.  
  4689.     /* Make sure the target is an lvalue */
  4690.  
  4691.     if  (!cmpCheckLvalue(dstx, false, true) && dstx->tnOper != TN_PROPERTY)
  4692.     {
  4693.         cmpCheckLvalue(dstx, false);
  4694.         return cmpCreateErrNode();
  4695.     }
  4696.  
  4697.     /* In general, we need to coerce the value to the target type */
  4698.  
  4699.     switch (oper)
  4700.     {
  4701.     default:
  4702.  
  4703.         srcx = cmpCastOfExpr(srcx, dstx->tnType, false);
  4704.         break;
  4705.  
  4706.     case TN_ASG_ADD:
  4707.     case TN_ASG_SUB:
  4708.  
  4709.         /* Special case: "ptr += int" or "ptr -= int' */
  4710.  
  4711.         if  (dstx->tnVtyp == TYP_PTR)
  4712.         {
  4713.             if  (cmpConfig.ccTgt64bit)
  4714.             {
  4715.                 if  (srcx->tnVtyp < TYP_NATINT || srcx->tnVtyp > TYP_ULONG)
  4716.                     srcx = cmpCoerceExpr(srcx, cmpTypeNatInt, false);
  4717.             }
  4718.             else
  4719.             {
  4720.                 if  (srcx->tnVtyp < TYP_INT || srcx->tnVtyp >= TYP_LONG)
  4721.                     srcx = cmpCoerceExpr(srcx, cmpTypeInt, false);
  4722.             }
  4723.  
  4724.             /* Scale the index value if necessary */
  4725.  
  4726.             srcx = cmpScaleIndex(srcx, dstType, TN_MUL);
  4727.  
  4728.             goto DONE;
  4729.         }
  4730.  
  4731.         srcx = cmpCastOfExpr(srcx, dstx->tnType, false);
  4732.         break;
  4733.  
  4734.     case TN_ASG_LSH:
  4735.     case TN_ASG_RSH:
  4736.     case TN_ASG_RSZ:
  4737.  
  4738.         /* Special case: if the second operand is 'long', make it 'int' */
  4739.  
  4740.         if  (dstx->tnVtyp == TYP_LONG)
  4741.         {
  4742.             srcx = cmpCoerceExpr(srcx, cmpTypeInt, false);
  4743.             break;
  4744.         }
  4745.  
  4746.         srcx = cmpCastOfExpr(srcx, dstx->tnType, false);
  4747.         break;
  4748.     }
  4749.  
  4750.     assert(srcx);
  4751.  
  4752.     /* Is this an assignment operator? */
  4753.  
  4754.     switch (oper)
  4755.     {
  4756.     case TN_ASG:
  4757.         break;
  4758.  
  4759.     case TN_ASG_ADD:
  4760.     case TN_ASG_SUB:
  4761.     case TN_ASG_MUL:
  4762.     case TN_ASG_DIV:
  4763.     case TN_ASG_MOD:
  4764.  
  4765.         /* The operands must be arithmetic */
  4766.  
  4767.         if  (varTypeIsArithmetic(dstVtyp))
  4768.             break;
  4769.  
  4770.         /* Wide characters are also OK in non-pedantic mode */
  4771.  
  4772.         if  (dstVtyp == TYP_WCHAR && !cmpConfig.ccPedantic)
  4773.             break;
  4774.  
  4775.         goto OP_ERR;
  4776.  
  4777.     case TN_ASG_AND:
  4778.  
  4779.         /* Strings are acceptable for "&=" */
  4780.  
  4781.         if  (cmpIsStringVal(dstx) && cmpIsStringVal(srcx))
  4782.             break;
  4783.  
  4784.     case TN_ASG_XOR:
  4785.     case TN_ASG_OR:
  4786.  
  4787.         /* The operands must be an integral type  */
  4788.  
  4789.         if  (varTypeIsIntegral(dstVtyp))
  4790.         {
  4791.             /* For enums and bools, the types better be identical */
  4792.  
  4793.             if  (varTypeIsArithmetic(srcx->tnVtypGet()) && varTypeIsArithmetic(dstVtyp))
  4794.                 break;
  4795.  
  4796.             if  (symTab::stMatchTypes(srcx->tnType, dstType))
  4797.                 break;
  4798.         }
  4799.  
  4800.         goto OP_ERR;
  4801.  
  4802.     case TN_ASG_LSH:
  4803.     case TN_ASG_RSH:
  4804.     case TN_ASG_RSZ:
  4805.  
  4806.         /* The operands must be integer */
  4807.  
  4808.         if  (varTypeIsIntegral(dstVtyp))
  4809.         {
  4810.             /* But not bool or enum! */
  4811.  
  4812.             if  (dstVtyp != TYP_BOOL && dstVtyp != TYP_ENUM)
  4813.                 break;
  4814.         }
  4815.  
  4816.         goto OP_ERR;
  4817.  
  4818.     default:
  4819.         assert(!"unexpected assignment operator");
  4820.     }
  4821.  
  4822.     /* Is this an assignment operator? */
  4823.  
  4824.     if  (oper != TN_ASG)
  4825.     {
  4826.         /* The result will be promoted to 'int' if it's any smaller */
  4827.  
  4828.         if  (dstType->tdTypeKind < TYP_INT)
  4829.             dstType = cmpTypeInt;
  4830.     }
  4831.  
  4832. DONE:
  4833.  
  4834.     if  (dstx->tnOper == TN_PROPERTY)
  4835.         return  cmpBindProperty(dstx, NULL, srcx);
  4836.  
  4837.     /* Return an assignment node */
  4838.  
  4839.     return  cmpCreateExprNode(expr, oper, dstType, dstx, srcx);
  4840.  
  4841. OP_ERR:
  4842.  
  4843.     if  (srcx->tnVtyp != TYP_UNDEF && dstx->tnVtyp != TYP_UNDEF)
  4844.     {
  4845.         cmpError(ERRoperType2,
  4846.                  cmpGlobalHT->tokenToIdent(treeOp2token(oper)),
  4847.                  dstx->tnType,
  4848.                  srcx->tnType);
  4849.     }
  4850.  
  4851.     return cmpCreateErrNode();
  4852. }
  4853.  
  4854. /*****************************************************************************
  4855.  *
  4856.  *  If the given expression is of a suitable type, make it into the boolean
  4857.  *  result, i.e. compare it against 0.
  4858.  */
  4859.  
  4860. Tree                compiler::cmpBooleanize(Tree expr, bool sense)
  4861. {
  4862.     if  (varTypeIsScalar(expr->tnVtypGet()))
  4863.     {
  4864.         Tree            zero;
  4865.  
  4866.         if  (expr->tnOperKind() & TNK_CONST)
  4867.         {
  4868.             switch (expr->tnOper)
  4869.             {
  4870.             case TN_CNS_INT:
  4871.  
  4872.                 expr->tnIntCon.tnIconVal = (!expr->tnIntCon.tnIconVal) ^ sense;
  4873.                 expr->tnVtyp             = TYP_BOOL;
  4874.                 expr->tnType             = cmpTypeBool;
  4875.  
  4876.                 return  expr;
  4877.  
  4878.             // ISSUE: fold long/float/double conditions as well, right?
  4879.             }
  4880.         }
  4881.  
  4882.         switch (expr->tnVtyp)
  4883.         {
  4884.         case TYP_LONG:
  4885.         case TYP_ULONG:
  4886.             zero = cmpCreateLconNode(NULL, 0, TYP_LONG);
  4887.             break;
  4888.  
  4889.         case TYP_REF:
  4890.         case TYP_PTR:
  4891.             zero = cmpCreateExprNode(NULL, TN_NULL, expr->tnType);
  4892.             break;
  4893.  
  4894.         default:
  4895.             zero = cmpCreateIconNode(NULL, 0, TYP_INT);
  4896.             break;
  4897.         }
  4898.  
  4899.         zero->tnType = expr->tnType;
  4900.         zero->tnVtyp = expr->tnVtypGet();
  4901.  
  4902.         expr = cmpCreateExprNode(NULL, sense ? TN_NE : TN_EQ,
  4903.                                        cmpTypeBool,
  4904.                                        expr,
  4905.                                        zero);
  4906.     }
  4907.  
  4908.     return  expr;
  4909. }
  4910.  
  4911. /*****************************************************************************
  4912.  *
  4913.  *  Bind the given tree and make sure it's a suitable condition expression.
  4914.  */
  4915.  
  4916. Tree                compiler::cmpBindCondition(Tree expr)
  4917. {
  4918.     expr = cmpBindExprRec(expr);
  4919.  
  4920.     /* In non-pedantic mode we allow any arithemtic type as a condition */
  4921.  
  4922.     if  (expr->tnVtyp != TYP_BOOL && !cmpConfig.ccPedantic)
  4923.     {
  4924.         switch (expr->tnOper)
  4925.         {
  4926.         case TN_EQ:
  4927.         case TN_NE:
  4928.         case TN_LT:
  4929.         case TN_LE:
  4930.         case TN_GE:
  4931.         case TN_GT:
  4932.  
  4933.             assert(expr->tnVtyp <= TYP_UINT);
  4934.  
  4935.             expr->tnType = cmpTypeBool;
  4936.             expr->tnVtyp = TYP_BOOL;
  4937.  
  4938.             break;
  4939.  
  4940.         default:
  4941.             expr = cmpBooleanize(expr, true);
  4942.             break;
  4943.         }
  4944.     }
  4945.  
  4946.     /* Make sure the result is 'boolean' */
  4947.  
  4948.     return  cmpCoerceExpr(expr, cmpTypeBool, false);
  4949. }
  4950.  
  4951. /*****************************************************************************
  4952.  *
  4953.  *  Multiply the expression by the size of the type pointed to by the given
  4954.  *  pointer type. The 'oper' argument should be TN_MUL or TN_DIV depending
  4955.  *  on whether the index is to be multiplied or divided.
  4956.  */
  4957.  
  4958. Tree                compiler::cmpScaleIndex(Tree expr, TypDef type, treeOps oper)
  4959. {
  4960.     size_t          size;
  4961.  
  4962.     assert(type->tdTypeKind == TYP_PTR || (type->tdTypeKind == TYP_REF && !type->tdIsManaged));
  4963.     assert(oper == TN_MUL || oper == TN_DIV);
  4964.  
  4965.     size = cmpGetTypeSize(cmpActualType(type->tdRef.tdrBase));
  4966.  
  4967.     if      (size == 0)
  4968.     {
  4969.         cmpError(ERRbadPtrUse, type);
  4970.     }
  4971.     else if (size > 1)
  4972.     {
  4973.         if  (expr->tnOper == TN_CNS_INT)
  4974.         {
  4975.             expr->tnIntCon.tnIconVal *= size;
  4976.         }
  4977.         else
  4978.         {
  4979.             Tree        cnsx;
  4980.  
  4981.             cnsx = cmpConfig.ccTgt64bit ? cmpCreateLconNode(NULL, size, TYP_ULONG)
  4982.                                         : cmpCreateIconNode(NULL, size, TYP_UINT);
  4983.  
  4984.             expr = cmpCreateExprNode(NULL, oper, expr->tnType, expr,
  4985.                                                                cnsx);
  4986.         }
  4987.     }
  4988.  
  4989.     return  expr;
  4990. }
  4991.  
  4992. /*****************************************************************************
  4993.  *
  4994.  *  Return true if the given expresion refers to a managed object.
  4995.  */
  4996.  
  4997. bool                compiler::cmpIsManagedAddr(Tree expr)
  4998. {
  4999.     switch (expr->tnOper)
  5000.     {
  5001.     case TN_LCL_SYM:
  5002.         return  false;
  5003.  
  5004.     case TN_INDEX:
  5005.         expr = expr->tnOp.tnOp1;
  5006.         if  (expr->tnVtyp != TYP_ARRAY)
  5007.             return  false;
  5008.         break;
  5009.  
  5010.     case TN_VAR_SYM:
  5011.         return  expr->tnVarSym.tnVarSym->sdIsManaged;
  5012.  
  5013.     case TN_IND:
  5014.         return  false;
  5015.  
  5016.     default:
  5017. #ifdef DEBUG
  5018.         cmpParser->parseDispTree(expr);
  5019.         printf("WARNING: unexpected value in cmpIsManagedAddr()\n");
  5020. #endif
  5021.         return  false;
  5022.     }
  5023.  
  5024.     return  expr->tnType->tdIsManaged;
  5025. }
  5026.  
  5027. /*****************************************************************************
  5028.  *
  5029.  *  Bind the given expression and return the bound and fully analyzed tree,
  5030.  *  or NULL if there were binding errors.
  5031.  */
  5032.  
  5033. Tree                compiler::cmpBindExprRec(Tree expr)
  5034. {
  5035.     SymTab          ourStab = cmpGlobalST;
  5036.  
  5037.     treeOps         oper;
  5038.     unsigned        kind;
  5039.  
  5040.     assert(expr);
  5041. #if!MGDDATA
  5042.     assert((int)expr != 0xDDDDDDDD && (int)expr != 0xCCCCCCCC);
  5043. #endif
  5044.  
  5045.     /* Get hold of the (unbound) operator */
  5046.  
  5047.     oper = expr->tnOperGet ();
  5048.     kind = expr->tnOperKind();
  5049.  
  5050.     /* Is this a constant node? */
  5051.  
  5052.     if  (kind & TNK_CONST)
  5053.     {
  5054.         /* In case we get an error ... */
  5055.  
  5056.         cmpRecErrorPos(expr);
  5057.  
  5058.         switch (oper)
  5059.         {
  5060.         case TN_CNS_STR:
  5061.  
  5062.             if      (expr->tnFlags & TNF_STR_ASCII)
  5063.             {
  5064.                 expr->tnType   = cmpTypeCharPtr;
  5065.                 expr->tnVtyp   = TYP_PTR;
  5066.             }
  5067.             else if (expr->tnFlags & TNF_STR_WIDE)
  5068.             {
  5069.                 expr->tnType   = cmpTypeWchrPtr;
  5070.                 expr->tnVtyp   = TYP_PTR;
  5071.             }
  5072.             else
  5073.             {
  5074.                 expr->tnType = cmpFindStringType();
  5075.                 expr->tnVtyp = TYP_REF;
  5076.             }
  5077.  
  5078.             break;
  5079.  
  5080.         case TN_NULL:
  5081.             expr->tnVtyp = TYP_REF;
  5082.             expr->tnType = cmpFindObjectType();
  5083.             break;
  5084.  
  5085.         default:
  5086.             if  (expr->tnVtyp != TYP_ENUM)
  5087.                 expr->tnType = ourStab->stIntrinsicType(expr->tnVtypGet());
  5088.             break;
  5089.         }
  5090.  
  5091. #ifdef  DEBUG
  5092.         expr->tnFlags |= TNF_BOUND;
  5093. #endif
  5094.  
  5095.         return  expr;
  5096.     }
  5097.  
  5098.     /* Is this a leaf node? */
  5099.  
  5100.     if  (kind & TNK_LEAF)
  5101.     {
  5102.         /* In case we get an error ... */
  5103.  
  5104.         cmpRecErrorPos(expr);
  5105.  
  5106.         switch (oper)
  5107.         {
  5108.         case TN_NAME:
  5109.             expr = cmpBindNameUse(expr, false, false);
  5110.             break;
  5111.  
  5112.         case TN_THIS:
  5113.  
  5114.             expr = cmpThisRef();
  5115.  
  5116.             /* In methods of managed value classes we implicitly fetch "*this" */
  5117.  
  5118.             if  (expr && cmpCurCls->sdType->tdClass.tdcValueType && cmpCurCls->sdIsManaged)
  5119.                 expr = cmpCreateExprNode(NULL, TN_IND, cmpCurCls->sdType, expr);
  5120.  
  5121.             break;
  5122.  
  5123.         case TN_BASE:
  5124.             expr = cmpThisRef();
  5125.             if  (expr->tnOper != TN_ERROR)
  5126.             {
  5127.                 TypDef          curTyp;
  5128.  
  5129.                 assert(expr->tnOper == TN_LCL_SYM);
  5130.                 assert(expr->tnType == cmpCurCls->sdType->tdClass.tdcRefTyp);
  5131.  
  5132.                 /* Figure out the base class (if there is one) */
  5133.  
  5134.                 curTyp = cmpCurCls->sdType;
  5135.  
  5136.                 /* Managed structs don't really have a base class */
  5137.  
  5138.                 if  (curTyp->tdClass.tdcValueType && curTyp->tdIsManaged)
  5139.                     curTyp = NULL;
  5140.                 else
  5141.                     curTyp = curTyp->tdClass.tdcBase;
  5142.  
  5143.                 /* Make sure this ref to "baseclass" is OK */
  5144.  
  5145.                 if  (curTyp)
  5146.                 {
  5147.                     expr->tnType   = curTyp->tdClass.tdcRefTyp;
  5148.                     expr->tnFlags |= TNF_LCL_BASE;
  5149.                 }
  5150.                 else
  5151.                     expr = cmpCreateErrNode(ERRbadBaseCall);
  5152.             }
  5153.             break;
  5154.  
  5155.         default:
  5156. #ifdef DEBUG
  5157.             cmpParser->parseDispTree(expr);
  5158. #endif
  5159.             assert(!"unexpected leaf node");
  5160.         }
  5161.  
  5162. #ifdef  DEBUG
  5163.         expr->tnFlags |= TNF_BOUND;
  5164. #endif
  5165.  
  5166.         return  expr;
  5167.     }
  5168.  
  5169.     /* Is it a 'simple' unary/binary operator? */
  5170.  
  5171.     if  (kind & TNK_SMPOP)
  5172.     {
  5173.         Tree            op1 = expr->tnOp.tnOp1;
  5174.         Tree            op2 = expr->tnOp.tnOp2;
  5175.  
  5176.         var_types       tp1;
  5177.         var_types       tp2;
  5178.  
  5179.         bool            mv1 = false;
  5180.         bool            mv2 = false;
  5181.  
  5182.         var_types       rvt;
  5183.         var_types       pvt;
  5184.  
  5185.         /* If this is an assignment, mark the target */
  5186.  
  5187.         if  (kind & TNK_ASGOP)
  5188.             op1->tnFlags |= TNF_ASG_DEST;
  5189.  
  5190.         /* Check for a few special cases first */
  5191.  
  5192.         switch (oper)
  5193.         {
  5194.             TypDef          type;
  5195.             size_t          size;
  5196.  
  5197.         case TN_DOT:
  5198.         case TN_ARROW:
  5199.             return  cmpBindDotArr(expr, false, false);
  5200.  
  5201.         case TN_CALL:
  5202.             return  cmpBindCall(expr);
  5203.  
  5204.         case TN_CAST:
  5205.  
  5206.             /* Bind the type reference and the operand */
  5207.  
  5208.             op1 = cmpBindExprRec(op1);
  5209.             if  (op1->tnVtyp == TYP_UNDEF)
  5210.                 return op1;
  5211.  
  5212.             /* Get hold of the target type and check it */
  5213.  
  5214.             type = cmpBindExprType(expr);
  5215.  
  5216.             /* Are the types identical? */
  5217.  
  5218.             if  (type->tdTypeKind == op1->tnVtyp &&
  5219.                  varTypeIsArithmetic(op1->tnVtypGet()))
  5220.             {
  5221.                 // UNDONE: Mark op1 as non-lvalue, right?
  5222.  
  5223.                 return  op1;
  5224.             }
  5225.  
  5226.             /* In case we get an error ... */
  5227.  
  5228.             cmpRecErrorPos(expr);
  5229.  
  5230.             /* Now perform the coercion */
  5231.  
  5232.             return cmpCoerceExpr(op1, type, (expr->tnFlags & TNF_EXP_CAST) != 0);
  5233.  
  5234.         case TN_LOG_OR:
  5235.         case TN_LOG_AND:
  5236.  
  5237.             /* Both operands must be conditions */
  5238.  
  5239.             op1 = cmpBindCondition(op1);
  5240.             op2 = cmpBindCondition(op2);
  5241.  
  5242.             /* The result will be boolean, of course */
  5243.  
  5244.             rvt = TYP_BOOL;
  5245.  
  5246.             // UNDONE: try to fold the condition
  5247.  
  5248.             goto RET_TP;
  5249.  
  5250.         case TN_LOG_NOT:
  5251.  
  5252.             /* The operand must be a condition */
  5253.  
  5254.             op1 = cmpBindCondition(op1);
  5255.             rvt = TYP_BOOL;
  5256.  
  5257.             goto RET_TP;
  5258.  
  5259.         case TN_NEW:
  5260.             return  cmpBindNewExpr(expr);
  5261.  
  5262.         case TN_ISTYPE:
  5263.  
  5264.             /* Bind the type reference and the operand */
  5265.  
  5266.             op1 = cmpBindExpr(op1);
  5267.             if  (op1->tnVtyp == TYP_UNDEF)
  5268.                 return op1;
  5269.  
  5270.             /* Get hold of the type and check it */
  5271.  
  5272.             type = cmpBindExprType(expr);
  5273.  
  5274.             /* Both operands must be classes or arrays */
  5275.  
  5276.             switch (cmpActualVtyp(op1->tnType))
  5277.             {
  5278.                 TypDef          optp;
  5279.  
  5280.             case TYP_REF:
  5281.             case TYP_ARRAY:
  5282.                 break;
  5283.  
  5284.             case TYP_VOID:
  5285.                 goto OP_ERR;
  5286.  
  5287.             default:
  5288.  
  5289.                 /* Switch to the equivalent struct type */
  5290.  
  5291.                 optp = cmpCheck4valType(op1->tnType);
  5292.                 if  (!optp)
  5293.                     goto OP_ERR;
  5294.  
  5295.                 op1->tnVtyp = TYP_CLASS;
  5296.                 op1->tnType = optp;
  5297.  
  5298.                 /* Box the sucker -- no doubt this is what the programmer wants */
  5299.  
  5300.                 op1 = cmpCreateExprNode(NULL, TN_BOX, optp->tdClass.tdcRefTyp, op1);
  5301.                 break;
  5302.             }
  5303.  
  5304.             switch (type->tdTypeKind)
  5305.             {
  5306.             case TYP_REF:
  5307.                 type = type->tdRef.tdrBase;
  5308.                 break;
  5309.  
  5310.             case TYP_CLASS:
  5311.             case TYP_ARRAY:
  5312.                 break;
  5313.  
  5314.             default:
  5315.                 type = cmpCheck4valType(type);
  5316.                 if  (!type)
  5317.                     goto OP_ERR;
  5318.                 break;
  5319.             }
  5320.  
  5321.             expr->tnOper               = TN_ISTYPE;
  5322.  
  5323.             expr->tnVtyp               = TYP_BOOL;
  5324.             expr->tnType               = cmpTypeBool;
  5325.  
  5326.             expr->tnOp.tnOp1           = op1;
  5327.             expr->tnOp.tnOp2           = cmpCreateExprNode(NULL, TN_NONE, type);
  5328.  
  5329.             /* Does the type reference a generic type argument ? */
  5330.  
  5331.             if  (type->tdTypeKind == TYP_CLASS &&
  5332.                  type->tdClass.tdcSymbol->sdClass.sdcGenArg)
  5333.             {
  5334.                 UNIMPL(!"sorry, 'istype' against generic type argument NYI");
  5335.             }
  5336.  
  5337.             return  expr;
  5338.  
  5339.         case TN_QMARK:
  5340.             return  cmpBindQmarkExpr(expr);
  5341.  
  5342.         case TN_SIZEOF:
  5343.         case TN_TYPEOF:
  5344.         case TN_ARR_LEN:
  5345.  
  5346.             if  (op1)
  5347.             {
  5348.                 /* Bind the operand so that we can see its type */
  5349.  
  5350.                 switch (op1->tnOper)
  5351.                 {
  5352.                 case TN_ANY_SYM:
  5353.  
  5354.                     // UNDONE: Tell cmpBindName() that we just need the type of the expr
  5355.  
  5356.                     op1 = cmpBindNameUse(op1, false, true);
  5357.  
  5358.                     if  (op1->tnOper == TN_CLASS)
  5359.                     {
  5360.                         expr->tnType = type = op1->tnType;
  5361.  
  5362.                         /* Pretend there was no operand, just the type */
  5363.  
  5364.                         op1  = NULL;
  5365.                     }
  5366.                     break;
  5367.  
  5368.                 case TN_NAME:
  5369.                     op1->tnFlags |= TNF_NAME_TYPENS;
  5370.                     op1 = cmpBindNameUse(op1, false, true);
  5371.                     break;
  5372.  
  5373.                 case TN_DOT:
  5374.                 case TN_ARROW:
  5375.                     op1 = cmpBindDotArr(op1, false, true);
  5376.                     break;
  5377.  
  5378.                 default:
  5379.                     op1 = cmpBindExprRec(op1);
  5380.                     break;
  5381.                 }
  5382.  
  5383.                 /*
  5384.                     Check for the ugly case: "sizeof(arrayvar)" is tricky,
  5385.                     because the array normally decays into a pointer, so
  5386.                     we need to see if that's happened and "undo" it.
  5387.                  */
  5388.  
  5389.                 if  (op1)
  5390.                 {
  5391.                     type = op1->tnType;
  5392.  
  5393.                     switch (op1->tnOper)
  5394.                     {
  5395.                     case TN_ADDROF:
  5396.                         if  (op1->tnFlags & TNF_ADR_IMPLICIT)
  5397.                         {
  5398.                             assert((op1->tnFlags & TNF_BEEN_CAST) == 0);
  5399.  
  5400.                             type = op1->tnOp.tnOp1->tnType;
  5401.  
  5402.                             assert(type->tdTypeKind == TYP_ARRAY);
  5403.                         }
  5404.                         break;
  5405.  
  5406.                     case TN_CLASS:
  5407.                         op1 = NULL;
  5408.                         break;
  5409.  
  5410.                     case TYP_UNDEF:
  5411.                         return  op1;
  5412.                     }
  5413.                 }
  5414.             }
  5415.             else
  5416.                 type = expr->tnType;
  5417.  
  5418.             if  (oper == TN_TYPEOF)
  5419.             {
  5420.                 /* Make sure the type looks OK */
  5421.  
  5422.                 cmpBindType(type, false, false);
  5423.  
  5424.             CHKTPID:
  5425.  
  5426.                 switch (type->tdTypeKind)
  5427.                 {
  5428.                 case TYP_REF:
  5429.                 case TYP_PTR:
  5430.                     type = type->tdRef.tdrBase;
  5431.                     goto CHKTPID;
  5432.  
  5433.                 case TYP_ENUM:
  5434.                     type->tdIsManaged = true;
  5435.                     break;
  5436.  
  5437.                 case TYP_REFANY:
  5438.  
  5439.                     expr->tnOp.tnOp1  = op1;
  5440.  
  5441.                     expr->tnType      = cmpTypeRef();
  5442.                     expr->tnVtyp      = TYP_REF;
  5443.  
  5444.                     return  expr;
  5445.  
  5446.                 case TYP_CLASS:
  5447.                 case TYP_ARRAY:
  5448.                     if  (type->tdIsManaged)
  5449.                         break;
  5450.  
  5451.                     // Fall through ....
  5452.  
  5453.                 default:
  5454.  
  5455.                     if  (type->tdTypeKind > TYP_lastIntrins)
  5456.                     {
  5457.                         cmpError(ERRtypeidOp, expr->tnType);
  5458.                         return cmpCreateErrNode();
  5459.                     }
  5460.  
  5461.                     type = cmpFindStdValType(type->tdTypeKindGet());
  5462.                     break;
  5463.                 }
  5464.  
  5465.                 /* Do we have a suitable instance? */
  5466.  
  5467.                 if  (op1 && !type->tdClass.tdcValueType)
  5468.                 {
  5469.                     SymDef          gsym;
  5470.                     Tree            call;
  5471.  
  5472.                     assert(op1->tnVtyp == TYP_REF || op1->tnVtyp == TYP_ARRAY);
  5473.  
  5474.                     /* Change the expression to "expr.GetClass()" */
  5475.  
  5476.                     gsym = cmpGlobalST->stLookupClsSym(cmpIdentGetType, cmpClassObject);
  5477.                     if  (!gsym)
  5478.                     {
  5479.                         UNIMPL(!"can this ever happen?");
  5480.                     }
  5481.  
  5482.                     call = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpTypeRef());
  5483.  
  5484.                     call->tnFncSym.tnFncObj  = op1;
  5485.                     call->tnFncSym.tnFncSym  = gsym;
  5486.                     call->tnFncSym.tnFncArgs = NULL;
  5487.                     call->tnFncSym.tnFncScp  = NULL;
  5488.  
  5489.                     return  call;
  5490.                 }
  5491.                 else
  5492.                 {
  5493.                     /* We'll have to make up an instance for the typeinfo */
  5494.  
  5495.                     return cmpTypeIDinst(type);
  5496.                 }
  5497.             }
  5498.  
  5499.             if  (oper == TN_ARR_LEN)
  5500.             {
  5501.                 if  (type->tdTypeKind != TYP_ARRAY)
  5502.                 {
  5503.                 BAD_ARR_LEN:
  5504.                     cmpError(ERRbadArrLen, type); size = 1;
  5505.                 }
  5506.                 else
  5507.                 {
  5508.                     if  (type->tdIsManaged)
  5509.                     {
  5510.                         rvt = TYP_UINT;
  5511.                         goto RET_TP;
  5512.                     }
  5513.                     else
  5514.                     {
  5515.                         DimDef          dims = type->tdArr.tdaDims;
  5516.  
  5517.                         assert(dims && dims->ddNext == NULL);
  5518.  
  5519.                         if  (dims->ddNoDim)
  5520.                             goto BAD_ARR_LEN;
  5521.                         if  (dims->ddIsConst == false)
  5522.                             goto BAD_ARR_LEN;
  5523.  
  5524.                         size = dims->ddSize;
  5525.                     }
  5526.                 }
  5527.             }
  5528.             else
  5529.             {
  5530.                 if  (type->tdIsManaged || type->tdTypeKind == TYP_NATINT
  5531.                                        || type->tdTypeKind == TYP_NATUINT)
  5532.                 {
  5533.                     cmpError(ERRbadSizeof, type);
  5534.                     return cmpCreateErrNode();
  5535.                 }
  5536.  
  5537.                 size = cmpGetTypeSize(type);
  5538.             }
  5539.  
  5540.             expr = cmpCreateIconNode(expr, size, TYP_UINT);
  5541.  
  5542. #ifdef  DEBUG
  5543.             expr->tnFlags |= TNF_BOUND;
  5544. #endif
  5545.  
  5546.             return  expr;
  5547.  
  5548.         case TN_INDEX:
  5549.  
  5550.             /*
  5551.                 Bind the first operand and see if it's a property. As a hack,
  5552.                 we prevent property binding by bashing the assignment flag.
  5553.              */
  5554.  
  5555.             op1->tnFlags |=  TNF_ASG_DEST;
  5556.             op1 = (op1->tnOper == TN_NAME) ? cmpBindName(op1, false, false)
  5557.                                            : cmpBindExprRec(op1);
  5558.             op1->tnFlags &= ~TNF_ASG_DEST;
  5559.  
  5560.             tp1 = op1->tnVtypGet();
  5561.             if  (tp1 == TYP_UNDEF)
  5562.                 return op1;
  5563.  
  5564.             assert(tp1 != TYP_TYPEDEF);
  5565.  
  5566.             /* Is this an indexed property access? */
  5567.  
  5568.             if  (op1->tnOper == TN_PROPERTY)
  5569.             {
  5570.                 /* Bind the second operand */
  5571.  
  5572.                 op2 = cmpBindExprRec(op2);
  5573.                 tp2 = op2->tnVtypGet();
  5574.                 if  (tp2 == TYP_UNDEF)
  5575.                     return op2;
  5576.  
  5577.                 /* Wrap 'op2' into an argument list entry node */
  5578.  
  5579.                 if  (op2->tnOper != TN_LIST)
  5580.                     op2 = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, op2, NULL);
  5581.  
  5582.                 /* Is this an assignment target? */
  5583.  
  5584.                 if  (expr->tnFlags & TNF_ASG_DEST)
  5585.                 {
  5586.                     /* Return the property to the caller for processing */
  5587.  
  5588.                     assert(op1->tnVarSym.tnVarObj);
  5589.                     assert(op1->tnVarSym.tnVarObj->tnOper != TN_LIST);
  5590.  
  5591.                     op1->tnVarSym.tnVarObj = cmpCreateExprNode(NULL,
  5592.                                                                TN_LIST,
  5593.                                                                cmpTypeVoid,
  5594.                                                                op1->tnVarSym.tnVarObj,
  5595.                                                                op2);
  5596.  
  5597.                     return  op1;
  5598.                 }
  5599.                 else
  5600.                 {
  5601.                     /* Go and bind the property reference */
  5602.  
  5603.                     return  cmpBindProperty(op1, op2, NULL);
  5604.                 }
  5605.             }
  5606.  
  5607.             goto BOUND_OP1;
  5608.  
  5609.         case TN_ADD:
  5610.  
  5611.             /* Is this a recursive call? */
  5612.  
  5613.             if  (expr->tnFlags & TNF_ADD_NOCAT)
  5614.             {
  5615.                 tp1 = op1->tnVtypGet();
  5616.                 if  (tp1 == TYP_UNDEF)
  5617.                     return op1;
  5618.  
  5619.                 assert(tp1 != TYP_TYPEDEF);
  5620.  
  5621.                 if  (varTypeIsArithmetic(tp1))
  5622.                     mv1 = true;
  5623.  
  5624.                 tp2 = op2->tnVtypGet();
  5625.                 if  (tp2 == TYP_UNDEF)
  5626.                     return op2;
  5627.  
  5628.                 assert(tp2 != TYP_TYPEDEF);
  5629.  
  5630.                 if  (varTypeIsArithmetic(tp2))
  5631.                     mv2 = true;
  5632.  
  5633.                 goto BOUND;
  5634.             }
  5635.  
  5636.             if  (cmpFindStringType())
  5637.             {
  5638.                 cmpWarn(WRNaddStrings);
  5639.                 return  cmpBindConcat(expr);
  5640.             }
  5641.  
  5642.             break;
  5643.  
  5644.         case TN_ASG_CNC:
  5645.  
  5646.             expr->tnOp.tnOp1 = cmpBindExprRec(op1);
  5647.  
  5648.             // Fall through ...
  5649.  
  5650.         case TN_CONCAT:
  5651.  
  5652.             if  (cmpFindStringType())
  5653.                 return  cmpBindConcat(expr);
  5654.  
  5655.             break;
  5656.  
  5657.         case TN_ASG_ADD:
  5658.  
  5659.             /* Bind the target of the assignment and see if it's a string */
  5660.  
  5661.             op1 = cmpBindExprRec(op1);
  5662.             tp1 = op1->tnVtypGet();
  5663.             if  (tp1 == TYP_UNDEF)
  5664.                 return op1;
  5665.  
  5666.             assert(tp1 != TYP_TYPEDEF);
  5667.  
  5668.             if  (cmpIsStringExpr(op1))
  5669.             {
  5670.                 expr->tnOp.tnOp1 = op1;
  5671.  
  5672.                 cmpWarn(WRNaddStrings);
  5673.                 return  cmpBindConcat(expr);
  5674.             }
  5675.  
  5676.             goto BOUND_OP1;
  5677.  
  5678.         case TN_TOKEN:
  5679.  
  5680.             assert(op1 && op1->tnOper == TN_NOP);
  5681.             assert(op2 == NULL);
  5682.  
  5683.             expr->tnVtyp = TYP_CLASS;
  5684.             expr->tnType = cmpRThandleClsGet()->sdType;
  5685.  
  5686.             assert(expr->tnType->tdTypeKind == expr->tnVtyp);
  5687.  
  5688.             return  expr;
  5689.         }
  5690.  
  5691.         /* Bind the operand(s) of the unary/binary operator */
  5692.  
  5693.         if  (op1)
  5694.         {
  5695.             op1 = cmpBindExprRec(op1);
  5696.             tp1 = op1->tnVtypGet();
  5697.             if  (tp1 == TYP_UNDEF)
  5698.                 return op1;
  5699.  
  5700.         BOUND_OP1:
  5701.  
  5702.             assert(tp1 != TYP_TYPEDEF);
  5703.  
  5704.             if  (varTypeIsArithmetic(tp1))
  5705.                 mv1 = true;
  5706.         }
  5707.  
  5708.         if  (op2)
  5709.         {
  5710.             op2 = cmpBindExprRec(op2);
  5711.             tp2 = op2->tnVtypGet();
  5712.             if  (tp2 == TYP_UNDEF)
  5713.                 return op2;
  5714.  
  5715.             assert(tp2 != TYP_TYPEDEF);
  5716.  
  5717.             if  (varTypeIsArithmetic(tp2))
  5718.                 mv2 = true;
  5719.         }
  5720.  
  5721.     BOUND:
  5722.  
  5723.         /* In case we get an error ... */
  5724.  
  5725.         cmpRecErrorPos(expr);
  5726.  
  5727.         /* See if we have an 'interesting' operator */
  5728.  
  5729.         switch  (oper)
  5730.         {
  5731.             TypDef          type;
  5732.  
  5733.         case TN_ASG:
  5734.         case TN_ASG_ADD:
  5735.         case TN_ASG_SUB:
  5736.         case TN_ASG_MUL:
  5737.         case TN_ASG_DIV:
  5738.         case TN_ASG_MOD:
  5739.         case TN_ASG_AND:
  5740.         case TN_ASG_XOR:
  5741.         case TN_ASG_OR:
  5742.         case TN_ASG_LSH:
  5743.         case TN_ASG_RSH:
  5744.         case TN_ASG_RSZ:
  5745.             return  cmpBindAssignment(op1, op2, expr, oper);
  5746.  
  5747.         case TN_LIST:
  5748.             expr->tnVtyp = TYP_VOID;
  5749.             expr->tnType = cmpTypeVoid;
  5750.             goto RET_OP;
  5751.  
  5752.         case TN_ADD:
  5753.         case TN_SUB:
  5754.         case TN_MUL:
  5755.         case TN_DIV:
  5756.         case TN_MOD:
  5757.             break;
  5758.  
  5759.         case TN_EQ:
  5760.         case TN_NE:
  5761.  
  5762.             /* The result will have the type 'boolean' */
  5763.  
  5764.             rvt = TYP_BOOL;
  5765.  
  5766.             /* Classes can be compared for equality */
  5767.  
  5768.             if  ((tp1 == TYP_REF ||
  5769.                   tp1 == TYP_PTR ||
  5770.                   tp1 == TYP_ARRAY) && (tp2 == TYP_REF ||
  5771.                                         tp2 == TYP_PTR ||
  5772.                                         tp2 == TYP_ARRAY))
  5773.             {
  5774.                 if  (cmpConvergeValues(op1, op2))
  5775.                 {
  5776.                     if  (op1->tnType == cmpRefTpString &&
  5777.                          op1->tnType == cmpRefTpString)
  5778.                     {
  5779.                         if  (op1->tnOper != TN_NULL && op2->tnOper != TN_NULL)
  5780.                         {
  5781.                             /* Should we compare values or refs ? */
  5782.  
  5783.                             if  (cmpConfig.ccStrValCmp)
  5784.                             {
  5785.                                 cmpWarn(WRNstrValCmp);
  5786.  
  5787.                                 /* Make sure we have the string comparison method */
  5788.  
  5789.                                 if  (!cmpStrEquals)
  5790.                                     cmpStrEquals = cmpFindStrCompMF("Equals", true);
  5791.  
  5792.                                 /* Create a call to the method */
  5793.  
  5794.                                 return  cmpCallStrCompMF(expr, op1, op2, cmpStrEquals);
  5795.                             }
  5796.                             else
  5797.                             {
  5798.                                 cmpWarn(WRNstrRefCmp);
  5799.                             }
  5800.                         }
  5801.                     }
  5802.  
  5803.                     goto RET_TP;
  5804.                 }
  5805.             }
  5806.  
  5807.             /* Booleans can also be compared */
  5808.  
  5809.             if  (tp1 == TYP_BOOL && tp2 == TYP_BOOL)
  5810.             {
  5811.                 goto RET_TP;
  5812.             }
  5813.  
  5814.         case TN_LT:
  5815.         case TN_LE:
  5816.         case TN_GE:
  5817.         case TN_GT:
  5818.  
  5819.             /* The result will have the type 'boolean' */
  5820.  
  5821.             rvt = TYP_BOOL;
  5822.  
  5823.             /* Comparisons that are not == or != require arithmetic operands */
  5824.  
  5825.             if  (mv1 && mv2)
  5826.             {
  5827.  
  5828.             MATH_CMP:
  5829.  
  5830.                 pvt = tp1;
  5831.  
  5832.                 if (pvt < tp2)
  5833.                     pvt = tp2;
  5834.  
  5835.                 if (pvt < TYP_INT)
  5836.                     pvt = TYP_INT;
  5837.  
  5838.                 goto PROMOTE;
  5839.             }
  5840.  
  5841.             /* Pointers can be compared as a relation */
  5842.  
  5843.             if  (tp1 == TYP_PTR && tp2 == TYP_PTR)
  5844.             {
  5845.                 if  (cmpConvergeValues(op1, op2))
  5846.                     goto RET_TP;
  5847.             }
  5848.  
  5849.             /* Enums can also be compared */
  5850.  
  5851.             if      (tp1 == TYP_ENUM)
  5852.             {
  5853.                 if  (varTypeIsScalar(tp2))
  5854.                 {
  5855.                     TypDef          etp;
  5856.  
  5857.                     /* Is the second type an enum as well? */
  5858.  
  5859.                     if  (tp2 == TYP_ENUM)
  5860.                     {
  5861.                         /* Are these the same enum types? */
  5862.  
  5863.                         if  (symTab::stMatchTypes(op1->tnType, op2->tnType))
  5864.                         {
  5865.                             rvt = TYP_BOOL;
  5866.                             goto RET_TP;
  5867.                         }
  5868.  
  5869.                         cmpWarn(WRNenumComp);
  5870.                     }
  5871.  
  5872.                     /* Switch the first operand to its underlying type */
  5873.  
  5874.                     op1->tnType = etp = op1->tnType->tdEnum.tdeIntType;
  5875.                     op1->tnVtyp = tp1 = etp->tdTypeKindGet();
  5876.  
  5877.                     if  (tp2 == TYP_ENUM)
  5878.                         goto ENUM_CMP2;
  5879.  
  5880.                     goto MATH_CMP;
  5881.                 }
  5882.             }
  5883.             else if (tp2 == TYP_ENUM)
  5884.             {
  5885.                 TypDef          etp;
  5886.  
  5887.             ENUM_CMP2:
  5888.  
  5889.                 op2->tnType = etp = op2->tnType->tdEnum.tdeIntType;;
  5890.                 op2->tnVtyp = tp2 = etp->tdTypeKindGet();
  5891.  
  5892.                 goto MATH_CMP;
  5893.             }
  5894.  
  5895.             /* Wide characters can be compared, of course */
  5896.  
  5897.             if  (tp1 == TYP_WCHAR)
  5898.             {
  5899.                 if  (tp2 == TYP_WCHAR)
  5900.                     goto RET_TP;
  5901.  
  5902.                 if  (op2->tnOper == TN_CNS_INT && !(op2->tnFlags & TNF_BEEN_CAST))
  5903.                 {
  5904.                     /* Special case: wide character and character constant */
  5905.  
  5906.                     if  (op2->tnVtyp == TYP_CHAR)
  5907.                     {
  5908.                     WCH2:
  5909.                         op2->tnVtyp = TYP_WCHAR;
  5910.                         op2->tnType = ourStab->stIntrinsicType(TYP_WCHAR);
  5911.  
  5912.                         goto RET_TP;
  5913.                     }
  5914.  
  5915.                     /* Special case: allow compares of wchar and 0 */
  5916.  
  5917.                     if  (op2->tnVtyp == TYP_INT && op2->tnIntCon.tnIconVal == 0)
  5918.                         goto WCH2;
  5919.                 }
  5920.  
  5921.                 if  (!cmpConfig.ccPedantic)
  5922.                     goto INTREL;
  5923.             }
  5924.  
  5925.             if  (tp2 == TYP_WCHAR)
  5926.             {
  5927.                 if  (op1->tnOper == TN_CNS_INT && !(op1->tnFlags & TNF_BEEN_CAST))
  5928.                 {
  5929.                     /* Special case: wide character and character constant */
  5930.  
  5931.                     if  (op1->tnVtyp == TYP_CHAR)
  5932.                     {
  5933.                     WCH1:
  5934.                         op1->tnVtyp = TYP_WCHAR;
  5935.                         op1->tnType = ourStab->stIntrinsicType(TYP_WCHAR);
  5936.  
  5937.                         goto RET_TP;
  5938.                     }
  5939.  
  5940.                     /* Special case: allow compares of wchar and 0 */
  5941.  
  5942.                     if  (op1->tnVtyp == TYP_INT && op1->tnIntCon.tnIconVal == 0)
  5943.                         goto WCH1;
  5944.                 }
  5945.  
  5946.                 if  (!cmpConfig.ccPedantic)
  5947.                     goto INTREL;
  5948.             }
  5949.  
  5950.             /* Allow pointers to be compared against the constant 0 */
  5951.  
  5952.             if  (tp1 == TYP_PTR &&
  5953.                  tp2 == TYP_INT && op2->tnOper == TN_CNS_INT
  5954.                                 && op2->tnIntCon.tnIconVal == 0)
  5955.             {
  5956.                 if  (oper == TN_EQ || oper == TN_NE)
  5957.                 {
  5958.                     /* Bash the 0 constant to the pointer type */
  5959.  
  5960.                     op2->tnVtyp = TYP_PTR;
  5961.                     op2->tnType = op1->tnType;
  5962.  
  5963.                     goto RET_TP;
  5964.                 }
  5965.             }
  5966.  
  5967.             /* Booleans can also be compared */
  5968.  
  5969.             if  (tp1 == TYP_BOOL || tp2 == TYP_BOOL)
  5970.             {
  5971.                 /* Normally we require both comparands to be booleans */
  5972.  
  5973.                 if  (tp1 == TYP_BOOL && tp2 == TYP_BOOL)
  5974.                     goto RET_TP;
  5975.  
  5976.                 /* Here only one of the operands is 'bool' */
  5977.  
  5978.                 if  (!cmpConfig.ccPedantic)
  5979.                 {
  5980.  
  5981.                 INTREL:
  5982.  
  5983.                     if  (mv1)
  5984.                     {
  5985.                         pvt = tp1; if (pvt < TYP_INT) pvt = TYP_INT;
  5986.                         goto PROMOTE;
  5987.                     }
  5988.  
  5989.                     if  (mv2)
  5990.                     {
  5991.                         pvt = tp2; if (pvt < TYP_INT) pvt = TYP_INT;
  5992.                         goto PROMOTE;
  5993.                     }
  5994.                 }
  5995.             }
  5996.  
  5997.             /* Are both operands references ? */
  5998.  
  5999.             if  (tp1 == TYP_REF && tp2 == TYP_REF)
  6000.             {
  6001.                 /* Is this a string value comparison? */
  6002.  
  6003.                 if  (op1->tnType == cmpRefTpString &&
  6004.                      op1->tnType == cmpRefTpString && cmpConfig.ccStrValCmp)
  6005.                 {
  6006.                     cmpWarn(WRNstrValCmp);
  6007.  
  6008.                     /* Make sure we have the string comparison method */
  6009.  
  6010.                     if  (!cmpStrCompare)
  6011.                         cmpStrCompare = cmpFindStrCompMF("Compare", false);
  6012.  
  6013.                     /* Create a call to the method */
  6014.  
  6015.                     expr = cmpCallStrCompMF(expr, op1, op2, cmpStrCompare);
  6016.  
  6017.                     /* Compare the return value appropriately */
  6018.  
  6019.                     return  cmpCreateExprNode(NULL,
  6020.                                               oper,
  6021.                                               cmpTypeBool,
  6022.                                               expr,
  6023.                                               cmpCreateIconNode(NULL, 0, TYP_INT));
  6024.                 }
  6025.  
  6026.                 Tree            temp;
  6027.  
  6028. #pragma message("need to fill in code for class operator overloading")
  6029.  
  6030.                 temp = cmpCompareValues(expr, op1, op2);
  6031.                 if  (temp)
  6032.                     return  temp;
  6033.  
  6034.                 /* Managed byrefs can also be compared */
  6035.  
  6036.                 if  (cmpIsByRefType(op1->tnType) &&
  6037.                      cmpIsByRefType(op2->tnType))
  6038.                 {
  6039.                     if  (cmpConvergeValues(op1, op2))
  6040.                         goto RET_TP;
  6041.                 }
  6042.             }
  6043.  
  6044.             /* Last chance - check for overloaded operator */
  6045.  
  6046.             if  (tp1 == TYP_CLASS || tp2 == TYP_CLASS)
  6047.             {
  6048.                 Tree            temp;
  6049.  
  6050.                 temp = cmpCompareValues(expr, op1, op2);
  6051.                 if  (temp)
  6052.                     return  temp;
  6053.             }
  6054.  
  6055.             goto OP_ERR;
  6056.  
  6057.         case TN_LSH:
  6058.         case TN_RSH:
  6059.         case TN_RSZ:
  6060.  
  6061.             /* Integer values required */
  6062.  
  6063.             if  (varTypeIsIntegral(tp1) &&
  6064.                  varTypeIsIntegral(tp2))
  6065.             {
  6066.  
  6067.             INT_SHF:
  6068.  
  6069.                 /* Is either operand an enum? */
  6070.  
  6071.                 if  (tp1 == TYP_ENUM) tp1 = op1->tnType->tdEnum.tdeIntType->tdTypeKindGet();
  6072.                 if  (tp2 == TYP_ENUM) tp2 = op2->tnType->tdEnum.tdeIntType->tdTypeKindGet();
  6073.  
  6074.                 /* Promote 'op1' to be at least as large as 'op2' */
  6075.  
  6076.                 if  (tp1 < tp2)
  6077.                 {
  6078.                     op1 = cmpCoerceExpr(op1, op2->tnType, false);
  6079.                     tp1 = tp2;
  6080.                 }
  6081.  
  6082.                 /* If the second operand is 'long', make it 'int' */
  6083.  
  6084.                 if  (tp2 == TYP_LONG)
  6085.                     op2 = cmpCoerceExpr(op2, cmpTypeInt, true);
  6086.  
  6087.                 /* Optimize away shifts by 0 */
  6088.  
  6089.                 if  (op2->tnOper == TN_CNS_INT && op2->tnIntCon.tnIconVal == 0)
  6090.                 {
  6091.                     op1->tnFlags &= ~TNF_LVALUE;
  6092.                     return op1;
  6093.                 }
  6094.  
  6095.                 rvt = tp1;
  6096.                 goto RET_TP;
  6097.             }
  6098.  
  6099.             if  (!cmpConfig.ccPedantic)
  6100.             {
  6101.                 if  ((tp1 == TYP_WCHAR || varTypeIsIntegral(tp1)) &&
  6102.                      (tp2 == TYP_WCHAR || varTypeIsIntegral(tp2)))
  6103.                 {
  6104.                     goto INT_SHF;
  6105.                 }
  6106.             }
  6107.  
  6108.             goto OP_ERR;
  6109.  
  6110.         case TN_OR:
  6111.         case TN_AND:
  6112.         case TN_XOR:
  6113.  
  6114.             /* Integers are OK */
  6115.  
  6116.             if  (varTypeIsIntegral(tp1) &&
  6117.                  varTypeIsIntegral(tp2))
  6118.             {
  6119.                 /* Enum's can be bit'ed together, but the types better match */
  6120.  
  6121.                 if  (tp1 == TYP_ENUM || tp2 == TYP_ENUM)
  6122.                 {
  6123.                     /* If identical enum types are being or'd, leave the type alone */
  6124.  
  6125.                     if  (symTab::stMatchTypes(op1->tnType, op2->tnType))
  6126.                     {
  6127.                         expr->tnVtyp = tp1;
  6128.                         expr->tnType = op1->tnType;
  6129.  
  6130.                         goto RET_OP;
  6131.                     }
  6132.  
  6133.                     /* Promote any enum values to their base type */
  6134.  
  6135.                     if  (tp1 == TYP_ENUM)
  6136.                     {
  6137.                         TypDef          etp = op1->tnType->tdEnum.tdeIntType;
  6138.  
  6139.                         op1->tnType = etp;
  6140.                         op1->tnVtyp = tp1 = etp->tdTypeKindGet();
  6141.                         mv1 = true;
  6142.                     }
  6143.  
  6144.                     if  (tp2 == TYP_ENUM)
  6145.                     {
  6146.                         TypDef          etp = op2->tnType->tdEnum.tdeIntType;
  6147.  
  6148.                         op2->tnType = etp;
  6149.                         op2->tnVtyp = tp2 = etp->tdTypeKindGet();
  6150.                         mv2 = true;
  6151.                     }
  6152.                 }
  6153.  
  6154.                 if  (tp1 == TYP_BOOL && tp2 == TYP_BOOL)
  6155.                 {
  6156.                     rvt = TYP_BOOL;
  6157.                     goto RET_TP;
  6158.                 }
  6159.  
  6160.                 if  (varTypeIsIntArith(tp1) && varTypeIsIntArith(tp2))
  6161.                     goto INT_MATH;
  6162.             }
  6163.  
  6164.             if  (!cmpConfig.ccPedantic)
  6165.             {
  6166.                 if  ((tp1 == TYP_WCHAR || varTypeIsIntegral(tp1)) &&
  6167.                      (tp2 == TYP_WCHAR || varTypeIsIntegral(tp2)))
  6168.                 {
  6169.                     goto INT_MATH;
  6170.                 }
  6171.             }
  6172.  
  6173.             /* The last chance is "bool" */
  6174.  
  6175.             pvt = rvt = TYP_BOOL;
  6176.  
  6177.             goto PROMOTE;
  6178.  
  6179.         case TN_NOT:
  6180.  
  6181.             /* The operand must be an integer */
  6182.  
  6183.             if  (!varTypeIsIntArith(tp1))
  6184.             {
  6185.                 /* Actually, we'll take an enum as well */
  6186.  
  6187.                 if  (tp1 == TYP_ENUM)
  6188.                 {
  6189.                     expr->tnVtyp = tp1;
  6190.                     expr->tnType = op1->tnType;
  6191.  
  6192.                     goto RET_OP;
  6193.                 }
  6194.  
  6195.                 goto OP_ERR;
  6196.             }
  6197.  
  6198.             /* The result is at least 'int' */
  6199.  
  6200.             rvt = tp1;
  6201.             if  (rvt < TYP_INT)
  6202.                  rvt = TYP_INT;
  6203.  
  6204.             goto RET_TP;
  6205.  
  6206.         case TN_NOP:
  6207.         case TN_NEG:
  6208.  
  6209.             /* The operand must be arithmetic */
  6210.  
  6211.             if  (!varTypeIsArithmetic(tp1))
  6212.                 goto TRY_OVL;
  6213.  
  6214.             /* The result is at least 'int' */
  6215.  
  6216.             rvt = tp1;
  6217.             if  (rvt < TYP_INT)
  6218.                  rvt = TYP_INT;
  6219.  
  6220.             goto RET_TP;
  6221.  
  6222.         case TN_INC_PRE:
  6223.         case TN_DEC_PRE:
  6224.  
  6225.         case TN_INC_POST:
  6226.         case TN_DEC_POST:
  6227.  
  6228.             /* The operand better be an lvalue */
  6229.  
  6230.             if (!cmpCheckLvalue(op1, false))
  6231.                 return cmpCreateErrNode();
  6232.  
  6233.             /* The operand must be an arithmetic lvalue */
  6234.  
  6235.             if  (!mv1 && tp1 != TYP_WCHAR)
  6236.             {
  6237.                 /* Unmanaged pointers / managed byrefs are OK as well */
  6238.  
  6239.                 if  (tp1 != TYP_PTR && !cmpIsByRefType(op1->tnType))
  6240.                 {
  6241.                     if  (tp1 != TYP_ENUM || cmpConfig.ccPedantic)
  6242.                         goto TRY_OVL;
  6243.  
  6244.                     expr->tnVtyp = tp1;
  6245.                     expr->tnType = op1->tnType;
  6246.  
  6247.                     goto RET_OP;
  6248.                 }
  6249.  
  6250.                 /* Note: the IL generator does the scaling of the delta */
  6251.             }
  6252.  
  6253.             /* The result will have the same value as the operand */
  6254.  
  6255.             rvt = tp1;
  6256.  
  6257.             if  (rvt != TYP_PTR && !cmpIsByRefType(op1->tnType))
  6258.                 goto RET_TP;
  6259.  
  6260.             expr->tnVtyp = tp1;
  6261.             expr->tnType = op1->tnType;
  6262.  
  6263. //          if (rvt == TYP_REF)
  6264. //              rvt = TYP_REF;
  6265.  
  6266.             goto RET_OP;
  6267.  
  6268.         case TN_INDEX:
  6269.  
  6270.             /* Make sure the left operand is an array */
  6271.  
  6272.             if  (tp1 != TYP_ARRAY)
  6273.             {
  6274.                 if  (tp1 == TYP_PTR)
  6275.                 {
  6276.                     if  (cmpConfig.ccSafeMode)
  6277.                         cmpError(ERRsafeArrX);
  6278.                 }
  6279.                 else
  6280.                 {
  6281.                     if  (tp1 == TYP_REF)
  6282.                     {
  6283.                         TypDef          baseTyp = op1->tnType->tdRef.tdrBase;
  6284.  
  6285.                         if  (!baseTyp->tdIsManaged)
  6286.                             goto DO_INDX;
  6287.  
  6288.                     }
  6289.  
  6290.                     cmpError(ERRbadIndex, op1->tnType);
  6291.                     return cmpCreateErrNode();
  6292.                 }
  6293.             }
  6294.  
  6295.         DO_INDX:
  6296.  
  6297.             type = cmpDirectType(op1->tnType);
  6298.  
  6299.             /* Coerce all of the index values to 'int' or 'uint' */
  6300.  
  6301.             if  (op2->tnOper == TN_LIST)
  6302.             {
  6303.                 Tree            xlst = op2;
  6304.                 unsigned        xcnt = 0;
  6305.  
  6306.                 /* Only one index expression allowed with unmanaged arrays */
  6307.  
  6308.                 if  (!type->tdIsManaged)
  6309.                     return cmpCreateErrNode(ERRmanyUmgIxx);
  6310.  
  6311.                 do
  6312.                 {
  6313.                     Tree            indx;
  6314.  
  6315.                     assert(xlst->tnOper == TN_LIST);
  6316.                     indx = xlst->tnOp.tnOp1;
  6317.                     assert(indx);
  6318.  
  6319.                     if  (cmpConfig.ccTgt64bit)
  6320.                     {
  6321.                         if  (indx->tnVtyp < TYP_NATINT ||
  6322.                              indx->tnVtyp > TYP_ULONG)
  6323.                         {
  6324.                             xlst->tnOp.tnOp1 = cmpCoerceExpr(indx, cmpTypeNatUint, false);
  6325.                         }
  6326.                     }
  6327.                     else
  6328.                     {
  6329.                         if  (indx->tnVtyp != TYP_INT &&
  6330.                              indx->tnVtyp != TYP_UINT)
  6331.                         {
  6332.                             xlst->tnOp.tnOp1 = cmpCoerceExpr(indx, cmpTypeInt, false);
  6333.                         }
  6334.                     }
  6335.  
  6336.                     xcnt++;
  6337.  
  6338.                     xlst = xlst->tnOp.tnOp2;
  6339.                 }
  6340.                 while (xlst);
  6341.  
  6342.                 /* Make sure the dimension count is correct */
  6343.  
  6344.                 if  (type->tdArr.tdaDcnt != xcnt &&
  6345.                      type->tdArr.tdaDcnt != 0)
  6346.                 {
  6347.                     cmpGenError(ERRindexCnt, type->tdArr.tdaDcnt);
  6348.                     return cmpCreateErrNode();
  6349.                 }
  6350.             }
  6351.             else
  6352.             {
  6353.                 if  (cmpConfig.ccTgt64bit)
  6354.                 {
  6355.                     if  (op2->tnVtyp < TYP_NATINT ||
  6356.                          op2->tnVtyp > TYP_ULONG)
  6357.                     {
  6358.                         op2 = cmpCoerceExpr(op2, cmpTypeNatUint, false);
  6359.                     }
  6360.                 }
  6361.                 else
  6362.                 {
  6363.                     if  (op2->tnVtyp != TYP_INT &&
  6364.                          op2->tnVtyp != TYP_UINT)
  6365.                     {
  6366.                         op2 = cmpCoerceExpr(op2, cmpTypeInt    , false);
  6367.                     }
  6368.                 }
  6369.  
  6370.                 /* Are we indexing into a managed array? */
  6371.  
  6372.                 if  (type->tdIsManaged)
  6373.                 {
  6374.                     /* Make sure the dimension count is correct */
  6375.  
  6376.                     if  (type->tdArr.tdaDcnt != 1 &&
  6377.                          type->tdArr.tdaDcnt != 0)
  6378.                     {
  6379.                         cmpGenError(ERRindexCnt, type->tdArr.tdaDcnt);
  6380.                         return cmpCreateErrNode();
  6381.                     }
  6382.                 }
  6383.                 else
  6384.                 {
  6385.                     /* Scale the index value if necessary */
  6386.  
  6387.                     op2 = cmpScaleIndex(op2, op1->tnType, TN_MUL);
  6388.                 }
  6389.             }
  6390.  
  6391.             /* The result will have the type of the array element */
  6392.  
  6393.             expr->tnFlags   |= TNF_LVALUE;
  6394.             expr->tnOp.tnOp1 = op1;
  6395.             expr->tnOp.tnOp2 = op2;
  6396.             expr->tnType     = cmpDirectType(op1->tnType->tdArr.tdaElem);
  6397.             expr->tnVtyp     = expr->tnType->tdTypeKind;
  6398.  
  6399.             return  cmpDecayCheck(expr);
  6400.  
  6401.         case TN_IND:
  6402.  
  6403.             if  (cmpConfig.ccSafeMode)
  6404.                 return  cmpCreateErrNode(ERRsafeInd);
  6405.  
  6406.             if  (tp1 != TYP_PTR && (tp1 != TYP_REF || op1->tnType->tdIsManaged))
  6407.             {
  6408.             IND_ERR:
  6409.                 cmpError(ERRbadIndir, op1->tnType);
  6410.                 return cmpCreateErrNode();
  6411.             }
  6412.  
  6413.             type = cmpDirectType(op1->tnType->tdRef.tdrBase);
  6414.             if  (type->tdTypeKind == TYP_VOID)
  6415.                 goto IND_ERR;
  6416.             if  (type->tdTypeKind == TYP_FNC)
  6417.                 goto IND_ERR;
  6418.  
  6419.             /* The result will have the type of the pointer base type  */
  6420.  
  6421.             expr->tnFlags   |= TNF_LVALUE;
  6422.             expr->tnOp.tnOp1 = op1;
  6423.             expr->tnOp.tnOp2 = op2;
  6424.             expr->tnType     = type;
  6425.             expr->tnVtyp     = type->tdTypeKind;
  6426.  
  6427.             return  cmpDecayCheck(expr);
  6428.  
  6429.         case TN_ADDROF:
  6430.  
  6431.             /* Is the operand a decayed array? */
  6432.  
  6433.             if  (op1->tnOper == TN_ADDROF && (op1->tnFlags & TNF_ADR_IMPLICIT))
  6434.             {
  6435.                 /* Simply bash the type of the implicit "address of" operator */
  6436.  
  6437.                 expr->tnOp.tnOp1 = op1 = op1->tnOp.tnOp1;
  6438.             }
  6439.             else
  6440.             {
  6441.                 /* Make sure the operand is an lvalue */
  6442.  
  6443.                 if (!cmpCheckLvalue(op1, true))
  6444.                     return cmpCreateErrNode();
  6445.             }
  6446.  
  6447.             /* Special case: "&(((foo*)0)->mem" can be folded */
  6448.  
  6449.             if  (op1->tnOper == TN_VAR_SYM && op1->tnVarSym.tnVarObj)
  6450.             {
  6451.                 unsigned        ofs = 0;
  6452.                 Tree            obj;
  6453.  
  6454.                 /* Of course, we also have to check for nested members */
  6455.  
  6456.                 for (obj = op1; obj->tnOper == TN_VAR_SYM; obj = obj->tnVarSym.tnVarObj)
  6457.                 {
  6458.                     assert(obj->tnVarSym.tnVarSym->sdSymKind == SYM_VAR);
  6459.  
  6460.                     ofs += obj->tnVarSym.tnVarSym->sdVar.sdvOffset;
  6461.                 }
  6462.  
  6463.                 if  (obj->tnOper == TN_CNS_INT && !obj->tnIntCon.tnIconVal)
  6464.                 {
  6465.                     /* Replace the whole thing with the member's offset */
  6466.  
  6467.                     expr = cmpCreateIconNode(expr, ofs, TYP_UINT);
  6468.                 }
  6469.             }
  6470.  
  6471.             /* Create the resulting pointer/reference type */
  6472.  
  6473.             pvt = cmpIsManagedAddr(op1) ? TYP_REF
  6474.                                         : TYP_PTR;
  6475.  
  6476.             expr->tnType = cmpGlobalST->stNewRefType(pvt, op1->tnType);
  6477.             expr->tnVtyp = pvt;
  6478.  
  6479.             /* If we've folded the operator, return */
  6480.  
  6481.             if  (expr->tnOper == TN_CNS_INT)
  6482.             {
  6483. #ifdef  DEBUG
  6484.                 expr->tnFlags |= TNF_BOUND;
  6485. #endif
  6486.                 return  expr;
  6487.             }
  6488.  
  6489.             goto RET_OP;
  6490.  
  6491.         case TN_DELETE:
  6492.  
  6493.             if  (cmpConfig.ccSafeMode)
  6494.                 return  cmpCreateErrNode(ERRsafeDel);
  6495.  
  6496.             /* The operand must be a non-constant unmanaged class pointer */
  6497.  
  6498.             if  (tp1 != TYP_PTR || op1->tnType->tdRef.tdrBase->tdIsManaged)
  6499.                 return  cmpCreateErrNode(ERRbadDelete);
  6500.  
  6501.             /* This expression will yield no value */
  6502.  
  6503.             rvt = TYP_VOID;
  6504.  
  6505.             goto RET_TP;
  6506.  
  6507.         case TN_COMMA:
  6508.  
  6509.             expr->tnVtyp = tp2;
  6510.             expr->tnType = op2->tnType;
  6511.  
  6512.             goto RET_OP;
  6513.  
  6514.         case TN_THROW:
  6515.  
  6516.             /* Throw doesn't produce a value */
  6517.  
  6518.             expr->tnType = cmpTypeVoid;
  6519.             expr->tnVtyp = TYP_VOID;
  6520.  
  6521.             /* Is there an operand? */
  6522.  
  6523.             if  (!op1)
  6524.             {
  6525.                 /* This is a "rethrow" */
  6526.  
  6527.                 if  (!cmpInHndBlk)
  6528.                     cmpError(ERRbadReThrow);
  6529.  
  6530.                 return  expr;
  6531.             }
  6532.  
  6533.             /*
  6534.                 Make sure the operand a managed class reference derived
  6535.                 from 'Exception'.
  6536.              */
  6537.  
  6538.             if  (!cmpCheckException(op1->tnType))
  6539.                 cmpError(ERRbadEHtype, op1->tnType);
  6540.  
  6541.             expr->tnOper     = TN_THROW;
  6542.             expr->tnOp.tnOp1 = op1;
  6543.  
  6544.             /* If a statement follows, it will never be reached */
  6545.  
  6546.             cmpStmtReachable = false;
  6547.  
  6548.             return  expr;
  6549.  
  6550.         case TN_TYPE:
  6551.             cmpError(ERRbadTypeExpr, expr->tnType);
  6552.             return  cmpCreateErrNode();
  6553.  
  6554.         case TN_REFADDR:
  6555.  
  6556.             assert(op1);
  6557.             assert(op2 && op2->tnOper == TN_NONE);
  6558.  
  6559.             if  (op1->tnVtyp != TYP_REFANY)
  6560.             {
  6561.                 cmpError(ERRbadExpTp, cmpGlobalST->stIntrinsicType(TYP_REFANY), op1->tnType);
  6562.                 return  cmpCreateErrNode();
  6563.             }
  6564.  
  6565.             /* Create the resulting pointer type */
  6566.  
  6567.             expr->tnType = cmpGlobalST->stNewRefType(TYP_REF, op2->tnType);
  6568.             expr->tnVtyp = TYP_REF;
  6569.  
  6570.             goto RET_OP;
  6571.  
  6572.         case TN_INST_STUB:
  6573.             return  expr;
  6574.  
  6575.         case TN_DOT_NAME:
  6576.         case TN_ARR_INIT:
  6577. #ifdef DEBUG
  6578.             cmpParser->parseDispTree(expr);
  6579. #endif
  6580.             assert(!"should never encounter this node in cmpBindExprRec()");
  6581.  
  6582.         default:
  6583. #ifdef DEBUG
  6584.             cmpParser->parseDispTree(expr);
  6585. #endif
  6586.             assert(!"unexpected operator node");
  6587.         }
  6588.  
  6589.         /* Only binary operands allowed at this point for simplicity */
  6590.  
  6591.         assert(op1);
  6592.         assert(op2);
  6593.  
  6594.         /* At this point the operands must be arithmetic */
  6595.  
  6596.         if  (!mv1 || !mv2)
  6597.         {
  6598.             /* Check for some special cases (mixing of types, etc.) */
  6599.  
  6600.             switch (oper)
  6601.             {
  6602.             case TN_ADD:
  6603.  
  6604.                 /* Check for "ptr + int" or "byref + int" */
  6605.  
  6606.                 if  (tp1 == TYP_PTR || (tp1 == TYP_REF && !op1->tnType->tdIsManaged))
  6607.                 {
  6608.                     if  (!varTypeIsIntegral(tp2))
  6609.                         break;
  6610.  
  6611.                 MATH_PTR1:
  6612.  
  6613.                     /* Coerce the second operand to an integer value */
  6614.  
  6615.                     if  (cmpConfig.ccTgt64bit)
  6616.                     {
  6617.                         if  (tp2 != TYP_ULONG && tp2 != TYP_NATUINT)
  6618.                             op2 = cmpCoerceExpr(op2, cmpTypeNatInt, false);
  6619.                     }
  6620.                     else
  6621.                     {
  6622.                         if  (tp2 != TYP_UINT)
  6623.                             op2 = cmpCoerceExpr(op2, cmpTypeInt, false);
  6624.                     }
  6625.  
  6626.                     /* Scale the integer operand by the base type size */
  6627.  
  6628.                     op2 = cmpScaleIndex(op2, op1->tnType, TN_MUL);
  6629.  
  6630.                     /* The result will have the pointer type */
  6631.  
  6632.                     expr->tnVtyp = tp1;
  6633.                     expr->tnType = op1->tnType;
  6634.  
  6635.                     goto RET_OP;
  6636.                 }
  6637.  
  6638.                 /* Check for "int + ptr" or "int + byref" */
  6639.  
  6640.                 if  (tp2 == TYP_PTR  || (tp2 == TYP_REF && !op2->tnType->tdIsManaged))
  6641.                 {
  6642.                     if  (!varTypeIsIntegral(tp1))
  6643.                         break;
  6644.  
  6645.                     /* Coerce the first operand to an integer value */
  6646.  
  6647.                     if  (tp1 != TYP_UINT)
  6648.                         op1 = cmpCoerceExpr(op1, cmpTypeInt, false);
  6649.  
  6650.                     /* Scale the integer operand by the base type size */
  6651.  
  6652.                     op1 = cmpScaleIndex(op1, op2->tnType, TN_MUL);
  6653.  
  6654.                     /* The result will have the pointer type */
  6655.  
  6656.                     expr->tnVtyp = tp2;
  6657.                     expr->tnType = op2->tnType;
  6658.  
  6659.                     goto RET_OP;
  6660.                 }
  6661.  
  6662.                 /* Check for "enum/wchar + int" and "int + enum/wchar" */
  6663.  
  6664.                 if  ((tp1 == TYP_ENUM || tp1 == TYP_WCHAR) && varTypeIsIntegral(tp2) ||
  6665.                      (tp2 == TYP_ENUM || tp2 == TYP_WCHAR) && varTypeIsIntegral(tp1))
  6666.                 {
  6667.  
  6668.                 ENUM_MATH:
  6669.  
  6670.                     if  (tp1 == TYP_ENUM)
  6671.                         tp1 = op1->tnType->tdEnum.tdeIntType->tdTypeKindGet();
  6672.  
  6673.                     assert(varTypeIsIntegral(tp1));
  6674.  
  6675.                     if  (tp2 == TYP_ENUM)
  6676.                         tp2 = op2->tnType->tdEnum.tdeIntType->tdTypeKindGet();
  6677.  
  6678.                     assert(varTypeIsIntegral(tp2));
  6679.  
  6680.                 INT_MATH:
  6681.  
  6682.                     /* Promote to max(type,type2,int) */
  6683.  
  6684.                     rvt = tp1;
  6685.                     if  (rvt < tp2)
  6686.                          rvt = tp2;
  6687.                     if  (rvt < TYP_INT)
  6688.                          rvt = TYP_INT;
  6689.  
  6690.                     pvt = rvt; assert(rvt != TYP_ENUM);
  6691.  
  6692.                     goto PROMOTE;
  6693.                 }
  6694.                 break;
  6695.  
  6696.             case TN_SUB:
  6697.  
  6698.                 /* Check for "ptr/byref - int" and "ptr/byref - ptr/byref" */
  6699.  
  6700.                 if  (tp1 == TYP_PTR || cmpIsByRefType(op1->tnType))
  6701.                 {
  6702.                     if  (varTypeIsIntegral(tp2))
  6703.                         goto MATH_PTR1;
  6704.  
  6705.                     if  (tp2 != tp1)
  6706.                         break;
  6707.  
  6708.                     if  (!symTab::stMatchTypes(op1->tnType, op2->tnType))
  6709.                         break;
  6710.  
  6711.                     /* Subtract the pointers and divide by element size */
  6712.  
  6713.                     expr->tnVtyp     = TYP_INT;
  6714.                     expr->tnType     = cmpTypeInt;
  6715.                     expr->tnOp.tnOp1 = op1;
  6716.                     expr->tnOp.tnOp2 = op2;
  6717.  
  6718.                     expr = cmpScaleIndex(expr, op1->tnType, TN_DIV);
  6719.  
  6720.                     return  expr;
  6721.                 }
  6722.  
  6723.                 /* Check for "enum - int" and "int - enum" */
  6724.  
  6725.                 if  (tp1 == TYP_ENUM && varTypeIsIntegral(tp2) ||
  6726.                      tp2 == TYP_ENUM && varTypeIsIntegral(tp1))
  6727.                 {
  6728.                     goto ENUM_MATH;
  6729.                 }
  6730.  
  6731.                 if  (tp1 == TYP_WCHAR)
  6732.                 {
  6733.                     /*
  6734.                         Both "wchar - char const" and "wchar - wchar"
  6735.                         yield an int.
  6736.                      */
  6737.  
  6738.                     if  (tp2 == TYP_WCHAR ||
  6739.                          tp2 == TYP_CHAR && op2->tnOper == TN_CNS_INT)
  6740.                     {
  6741.                         rvt = TYP_INT;
  6742.                         goto RET_TP;
  6743.                     }
  6744.                 }
  6745.  
  6746.                 if  (!cmpConfig.ccPedantic)
  6747.                 {
  6748.                     if  (varTypeIsArithmetic(tp1) && (tp2 == TYP_WCHAR || tp2 == TYP_BOOL))
  6749.                         goto INT_MATH;
  6750.                     if  (varTypeIsArithmetic(tp2) && (tp1 == TYP_WCHAR || tp1 == TYP_BOOL))
  6751.                         goto INT_MATH;
  6752.                 }
  6753.  
  6754.                 break;
  6755.  
  6756.             case TN_MUL:
  6757.             case TN_DIV:
  6758.             case TN_MOD:
  6759.  
  6760.                 if  (cmpConfig.ccPedantic)
  6761.                     break;
  6762.  
  6763.                 if  (varTypeIsArithmetic(tp1))
  6764.                 {
  6765.                     if  (tp2 == TYP_ENUM)
  6766.                         goto ENUM_MATH;
  6767.                     if  (tp2 == TYP_WCHAR)
  6768.                         goto INT_MATH;
  6769.                 }
  6770.  
  6771.                 if  (varTypeIsArithmetic(tp2))
  6772.                 {
  6773.                     if  (tp1 == TYP_ENUM)
  6774.                         goto ENUM_MATH;
  6775.                     if  (tp1 == TYP_WCHAR)
  6776.                         goto INT_MATH;
  6777.                 }
  6778.  
  6779.                 break;
  6780.             }
  6781.  
  6782.         TRY_OVL:
  6783.  
  6784.             /* If either operand is a struct, check for an overloaded operator */
  6785.  
  6786.             if  (tp1 == TYP_CLASS || tp2 == TYP_CLASS)
  6787.             {
  6788.                 Tree        ovlx;
  6789.  
  6790.                 expr->tnOp.tnOp1 = op1;
  6791.                 expr->tnOp.tnOp2 = op2;
  6792.  
  6793.                 ovlx = cmpCheckOvlOper(expr);
  6794.                 if  (ovlx)
  6795.                     return  ovlx;
  6796.             }
  6797.  
  6798.             /* Jump here to report a generic "illegal type for operator" error */
  6799.  
  6800.         OP_ERR:
  6801.  
  6802.             if  (tp1 != TYP_UNDEF && tp2 != TYP_UNDEF)
  6803.             {
  6804.                 Ident       opnm = cmpGlobalHT->tokenToIdent(treeOp2token(oper));
  6805.  
  6806.                 if  (op2)
  6807.                     cmpError(ERRoperType2, opnm, op1->tnType, op2->tnType);
  6808.                 else
  6809.                     cmpError(ERRoperType , opnm, op1->tnType, false);
  6810.             }
  6811.  
  6812.             return cmpCreateErrNode();
  6813.         }
  6814.  
  6815.         /* Promote both operand to either 'int' or the 'bigger' of the two types */
  6816.  
  6817.         rvt = TYP_INT;
  6818.  
  6819.         if  (tp1 > TYP_INT || tp2 > TYP_INT)
  6820.         {
  6821.             rvt = tp1;
  6822.             if  (rvt < tp2)
  6823.                  rvt = tp2;
  6824.         }
  6825.  
  6826.         pvt = rvt;
  6827.  
  6828.         /*
  6829.             At this point, we have the following values:
  6830.  
  6831.                 rvt     ....    type of the result
  6832.                 pvt     ....    type the operands should be promoted to
  6833.          */
  6834.  
  6835.     PROMOTE:
  6836.  
  6837.         if  (tp1 != pvt) op1 = cmpCoerceExpr(op1, ourStab->stIntrinsicType(pvt), false);
  6838.         if  (tp2 != pvt) op2 = cmpCoerceExpr(op2, ourStab->stIntrinsicType(pvt), false);
  6839.  
  6840.     RET_TP:
  6841.  
  6842.         expr->tnVtyp = rvt;
  6843.         expr->tnType = ourStab->stIntrinsicType(rvt);
  6844.  
  6845.     RET_OP:
  6846.  
  6847.         expr->tnOp.tnOp1 = op1;
  6848.         expr->tnOp.tnOp2 = op2;
  6849.  
  6850. #ifdef  DEBUG
  6851.         expr->tnFlags |= TNF_BOUND;
  6852. #endif
  6853.  
  6854.         /* Check for an operator with a constant operand */
  6855.  
  6856.         if  (op1->tnOperKind() & TNK_CONST)
  6857.         {
  6858.             /* Some operators can never be folded */
  6859.  
  6860.             switch (oper)
  6861.             {
  6862.             case TN_LIST:
  6863.             case TN_COMMA:
  6864.                 return  expr;
  6865.             }
  6866.  
  6867.             /* Is this a unary or binary operator? */
  6868.  
  6869.             if  (op2)
  6870.             {
  6871.                 if  (op2->tnOperKind() & TNK_CONST)
  6872.                 {
  6873.                     switch (op1->tnOper)
  6874.                     {
  6875.                     case TN_CNS_INT: expr = cmpFoldIntBinop(expr); break;
  6876.                     case TN_CNS_LNG: expr = cmpFoldLngBinop(expr); break;
  6877.                     case TN_CNS_FLT: expr = cmpFoldFltBinop(expr); break;
  6878.                     case TN_CNS_DBL: expr = cmpFoldDblBinop(expr); break;
  6879.                     case TN_CNS_STR: expr = cmpFoldStrBinop(expr); break;
  6880.                     case TN_NULL: break;
  6881.                     default: NO_WAY(!"unexpected const type");
  6882.                     }
  6883.                 }
  6884.                 else
  6885.                 {
  6886.                     // UNDONE: Check for things such as "0 && expr"
  6887.                 }
  6888.             }
  6889.             else
  6890.             {
  6891.                 switch (op1->tnOper)
  6892.                 {
  6893.                 case TN_CNS_INT: expr = cmpFoldIntUnop(expr); break;
  6894.                 case TN_CNS_LNG: expr = cmpFoldLngUnop(expr); break;
  6895.                 case TN_CNS_FLT: expr = cmpFoldFltUnop(expr); break;
  6896.                 case TN_CNS_DBL: expr = cmpFoldDblUnop(expr); break;
  6897.                 case TN_CNS_STR: break;
  6898.                 default: NO_WAY(!"unexpected const type");
  6899.                 }
  6900.             }
  6901.         }
  6902.  
  6903.         return  expr;
  6904.     }
  6905.  
  6906.     /* See what kind of a special operator we have here */
  6907.  
  6908.     switch  (oper)
  6909.     {
  6910.     case TN_ANY_SYM:
  6911.         expr = cmpBindNameUse(expr, false, false);
  6912.         break;
  6913.  
  6914.     case TN_NONE:
  6915.         assert(expr->tnType);
  6916.         expr->tnVtyp = expr->tnType->tdTypeKindGet();
  6917.         break;
  6918.  
  6919.     case TN_ERROR:
  6920.         break;
  6921.  
  6922.     default:
  6923. #ifdef DEBUG
  6924.         cmpParser->parseDispTree(expr);
  6925. #endif
  6926.         assert(!"unexpected node");
  6927.     }
  6928.  
  6929. #ifdef  DEBUG
  6930.     expr->tnFlags |= TNF_BOUND;
  6931. #endif
  6932.  
  6933.     return  expr;
  6934. }
  6935.  
  6936. /*****************************************************************************
  6937.  *
  6938.  *  Bind an array bound expression.
  6939.  */
  6940.  
  6941. Tree                compiler::cmpBindArrayBnd(Tree expr)
  6942. {
  6943.     if  (expr)
  6944.     {
  6945.         expr = cmpBindExpr(expr);
  6946.  
  6947.         if  (expr->tnVtyp != TYP_UINT)
  6948.         {
  6949.             if  (expr->tnVtyp != TYP_INT || expr->tnOper == TN_CNS_INT)
  6950.             {
  6951.                 expr = cmpCoerceExpr(expr, cmpTypeUint, false);
  6952.             }
  6953.         }
  6954.     }
  6955.  
  6956.     return  expr;
  6957. }
  6958.  
  6959. /*****************************************************************************
  6960.  *
  6961.  *  Check an array type parse tree and return the corresponding type.
  6962.  */
  6963.  
  6964. void                compiler::cmpBindArrayType(TypDef type, bool needDef,
  6965.                                                             bool needDim,
  6966.                                                             bool mustDim)
  6967. {
  6968.     DimDef      dims = type->tdArr.tdaDims; assert(dims);
  6969.     TypDef      elem = cmpDirectType(type->tdArr.tdaElem);
  6970.  
  6971.     assert(type && type->tdTypeKind == TYP_ARRAY);
  6972.  
  6973.     /* Can't have an unmanaged array of managed types */
  6974.  
  6975.     if  (type->tdIsManaged == false &&
  6976.          elem->tdIsManaged != false)
  6977.     {
  6978.         type->tdIsManaged = elem->tdIsManaged;
  6979.  
  6980. //      cmpError(ERRbadRefArr, elem);
  6981.  
  6982.         if  (elem->tdTypeKind == TYP_CLASS)
  6983.         {
  6984.             if  (isMgdValueType(elem))
  6985.                 type->tdIsValArray = true;
  6986.         }
  6987.  
  6988.         assert(type->tdIsValArray == (type->tdIsManaged && isMgdValueType(cmpActualType(type->tdArr.tdaElem))));
  6989.     }
  6990.  
  6991.     /* Is this a managed array? */
  6992.  
  6993.     if  (type->tdIsManaged)
  6994.     {
  6995.         /* Is there any dimension at all? */
  6996.  
  6997.         if  (type->tdIsUndimmed)
  6998.         {
  6999.             /* Are we supposed to have a dimension here? */
  7000.  
  7001.             if  (needDim && (elem->tdTypeKind != TYP_ARRAY || mustDim))
  7002.                 cmpError(ERRnoArrDim);
  7003.         }
  7004.  
  7005.         /* Check all dimensions that were specified */
  7006.  
  7007.         while (dims)
  7008.         {
  7009.             if  (dims->ddNoDim)
  7010.             {
  7011.                 // UNDONE: What do we need to check here?
  7012.             }
  7013.             else
  7014.             {
  7015.                 assert(dims->ddDimBound == false);
  7016.  
  7017. #ifdef  DEBUG
  7018.                 dims->ddDimBound = true;
  7019. #endif
  7020.  
  7021.                 dims->ddLoTree   = cmpBindArrayBnd(dims->ddLoTree);
  7022.                 dims->ddHiTree   = cmpBindArrayBnd(dims->ddHiTree);
  7023.             }
  7024.  
  7025.             /* Continue with the next dimension */
  7026.  
  7027.             dims = dims->ddNext;
  7028.         }
  7029.  
  7030.         /* Now check the element type */
  7031.  
  7032.         cmpBindType(elem, needDef, needDim);
  7033.  
  7034.         /* Special handling needed for arrays of value types */
  7035.  
  7036.         if  (isMgdValueType(elem)) // && !type->tdArr.tdaArrCls)
  7037.         {
  7038.             /* Remember that this is an array of managed values */
  7039.  
  7040.             type->tdIsValArray = true;
  7041.         }
  7042.     }
  7043.     else
  7044.     {
  7045.         Tree            dimx;
  7046.  
  7047.         /* Is there a dimension at all? */
  7048.  
  7049.         if  (type->tdIsUndimmed)
  7050.         {
  7051.             /* Are we supposed to have a dimension here? */
  7052.  
  7053.             if  (needDim && (elem->tdTypeKind != TYP_ARRAY || mustDim))
  7054.                 cmpError(ERRnoArrDim);
  7055.  
  7056.             needDim = true;
  7057.  
  7058.             goto ELEM;
  7059.         }
  7060.  
  7061.         assert(dims);
  7062.         assert(dims->ddNoDim == false);
  7063.         assert(dims->ddNext  == NULL);
  7064.  
  7065.         /* Make sure the element type is not a managed type */
  7066.  
  7067.         if  (elem->tdIsManaged || elem->tdTypeKind == TYP_REF)
  7068.             cmpError(ERRbadRefArr, elem);
  7069.  
  7070.         /* Evaluate the dimension and make sure it's constant */
  7071.  
  7072.         dimx = cmpBindExpr(dims->ddLoTree);
  7073.  
  7074.         switch (dimx->tnVtyp)
  7075.         {
  7076.         case TYP_INT:
  7077.         case TYP_UINT:
  7078.         case TYP_NATINT:
  7079.         case TYP_NATUINT:
  7080.             break;
  7081.  
  7082.         default:
  7083.             dimx = cmpCoerceExpr(dimx, cmpTypeInt, false);
  7084.             break;
  7085.         }
  7086.  
  7087.         /* Now make sure we have a constant expression */
  7088.  
  7089.         dimx = cmpFoldExpression(dimx);
  7090.  
  7091.         switch (dimx->tnOper)
  7092.         {
  7093.         case TN_CNS_INT:
  7094.             dims->ddSize = dimx->tnIntCon.tnIconVal;
  7095.             if  (dims->ddSize > 0 || !needDim)
  7096.                 break;
  7097.  
  7098.             // Fall through ....
  7099.  
  7100.         default:
  7101.  
  7102.             if  (!needDim)
  7103.                 goto ELEM;
  7104.  
  7105.             cmpRecErrorPos(dimx);
  7106.             cmpError(ERRbadArrSize);
  7107.  
  7108.             // Fall through ....
  7109.  
  7110.         case TN_ERROR:
  7111.             dims->ddSize = 1;
  7112.             break;
  7113.         }
  7114.  
  7115.         dims->ddIsConst  = true;
  7116.  
  7117.     ELEM:
  7118.  
  7119. #ifndef NDEBUG
  7120.         dims->ddDimBound = true;
  7121. #endif
  7122.  
  7123.         cmpBindType(type->tdArr.tdaElem, needDef, needDim);
  7124.     }
  7125. }
  7126.  
  7127. /*****************************************************************************
  7128.  *
  7129.  *  Resolve a type reference within a parse tree.
  7130.  */
  7131.  
  7132. void                compiler::cmpBindType(TypDef type, bool needDef,
  7133.                                                        bool needDim)
  7134. {
  7135.     assert(type);
  7136.  
  7137. AGAIN:
  7138.  
  7139.     switch (type->tdTypeKind)
  7140.     {
  7141.         TypDef          btyp;
  7142.  
  7143.     case TYP_ARRAY:
  7144.         cmpBindArrayType(type, needDef, needDim, false);
  7145.         break;
  7146.  
  7147.     case TYP_CLASS:
  7148.         if  (needDef)
  7149.             cmpDeclSym(type->tdClass.tdcSymbol);
  7150. //      if  (type->tdIsManaged)
  7151. //          type = type->tdClass.tdcRefTyp;
  7152.         break;
  7153.  
  7154.     case TYP_TYPEDEF:
  7155.         cmpDeclSym(type->tdTypedef.tdtSym);
  7156.         type = type->tdTypedef.tdtType;
  7157.         goto AGAIN;
  7158.  
  7159.     case TYP_REF:
  7160.  
  7161.         btyp = type->tdRef.tdrBase; cmpBindType(btyp, needDef, needDim);
  7162.  
  7163. //      if  (btyp->tdIsManaged == false)
  7164. //          cmpError(ERRumgRef, type);
  7165.  
  7166.         break;
  7167.  
  7168.     case TYP_PTR:
  7169.  
  7170.         btyp = type->tdRef.tdrBase; cmpBindType(btyp, needDef, needDim);
  7171.  
  7172.         switch (btyp->tdTypeKind)
  7173.         {
  7174.         case TYP_CLASS:
  7175.             if  (btyp->tdClass.tdcValueType)
  7176.                 break;
  7177.             // Fall through ...
  7178.         case TYP_ARRAY:
  7179.             if  (!btyp->tdIsManaged)
  7180.                 break;
  7181.             // Fall through ...
  7182.         case TYP_REF:
  7183.             cmpError(ERRmgdPtr, type);
  7184.             break;
  7185.         }
  7186.         break;
  7187.  
  7188.     case TYP_FNC:
  7189.  
  7190.         btyp = type->tdFnc.tdfRett;
  7191.  
  7192.         /* Special case: reference return type */
  7193.  
  7194.         if  (btyp->tdTypeKind == TYP_REF)
  7195.         {
  7196.             if  (btyp->tdRef.tdrBase->tdTypeKind == TYP_VOID)
  7197.             {
  7198.                 type->tdFnc.tdfRett = cmpGlobalST->stIntrinsicType(TYP_REFANY);
  7199.             }
  7200.             else
  7201.             {
  7202.                 cmpBindType(btyp->tdFnc.tdfRett, false, false);
  7203.             }
  7204.         }
  7205.         else
  7206.             cmpBindType(btyp, false, false);
  7207.  
  7208.         // UNDONE: bind return type and all the argument types, right?
  7209.         // ISSUE: we should probably ban non-class return refs, right?
  7210.  
  7211.         break;
  7212.  
  7213.     case TYP_ENUM:
  7214.         if  (needDef)
  7215.             cmpDeclEnum(type->tdEnum.tdeSymbol);
  7216.         break;
  7217.  
  7218.     default:
  7219.         assert((unsigned)type->tdTypeKind <= TYP_lastIntrins);
  7220.         break;
  7221.     }
  7222. }
  7223.  
  7224. /*****************************************************************************
  7225.  *
  7226.  *  Bind an array initializer of the form "{ elem-expr, elem-expr, ... }".
  7227.  */
  7228.  
  7229. Tree                compiler::cmpBindArrayExpr(TypDef type, int      dimPos,
  7230.                                                             unsigned elems)
  7231. {
  7232.     Scanner         ourScanner = cmpScanner;
  7233.     Parser          ourParser  = cmpParser;
  7234.  
  7235.     TypDef          elem;
  7236.  
  7237.     Tree            list = NULL;
  7238.     Tree            last = NULL;
  7239.  
  7240.     bool            multi;
  7241.  
  7242.     unsigned        count;
  7243.     unsigned        subcnt = 0;
  7244.  
  7245.     assert(type->tdTypeKind == TYP_ARRAY && type->tdIsManaged);
  7246.  
  7247.     count = 0;
  7248.  
  7249.     assert(ourScanner->scanTok.tok == tkLCurly);
  7250.     if  (ourScanner->scan() == tkRCurly)
  7251.         goto DONE;
  7252.  
  7253.     elem = cmpDirectType(type->tdArr.tdaElem);
  7254.  
  7255.     /* Are we processing a multi-dimensional array initializer? */
  7256.  
  7257.     multi = false;
  7258.  
  7259.     if  (type->tdArr.tdaDims &&
  7260.          type->tdArr.tdaDims->ddNext)
  7261.     {
  7262.         /* This is a multi-dimensional rectangular array */
  7263.  
  7264.         if  (!dimPos)
  7265.         {
  7266.             /* We're at the outermost dimension, get things started */
  7267.  
  7268.             dimPos = 1;
  7269.             multi  = true;
  7270.  
  7271.             /* Pass the same array type on to the next level */
  7272.  
  7273.             elem = type;
  7274.         }
  7275.         else
  7276.         {
  7277.             DimDef          dims = type->tdArr.tdaDims;
  7278.             unsigned        dcnt;
  7279.  
  7280.             /* Do we have any dimensions left? */
  7281.  
  7282.             dcnt = dimPos++;
  7283.  
  7284.             do
  7285.             {
  7286.                 dims = dims->ddNext; assert(dims);
  7287.             }
  7288.             while (--dcnt);
  7289.  
  7290.             if  (dims->ddNext)
  7291.             {
  7292.                 /* There is another dimension to this array */
  7293.  
  7294.                 multi  = true;
  7295.  
  7296.                 /* Pass the same array type on to the next level */
  7297.  
  7298.                 elem   = type;
  7299.             }
  7300.             else
  7301.                 dimPos = 0;
  7302.         }
  7303.     }
  7304.     else
  7305.     {
  7306.         assert(dimPos == 0);
  7307.  
  7308.         if  (elem->tdTypeKind == TYP_ARRAY)
  7309.             multi = true;
  7310.     }
  7311.  
  7312.     for (count = 0;;)
  7313.     {
  7314.         Tree            init;
  7315.  
  7316.         count++;
  7317.  
  7318.         /* Are we expecting a nested array? */
  7319.  
  7320.         if  (ourScanner->scanTok.tok == tkLCurly)
  7321.         {
  7322.             if  (multi)
  7323.             {
  7324.                 /* Recursively process the nested initializer */
  7325.  
  7326.                 init = cmpBindArrayExpr(elem, dimPos, subcnt);
  7327.  
  7328.                 /* Check/record the element count */
  7329.  
  7330.                 if  (!subcnt && init->tnOper == TN_ARR_INIT)
  7331.                 {
  7332.                     assert(init->tnOp.tnOp2);
  7333.                     assert(init->tnOp.tnOp2->tnOper == TN_CNS_INT);
  7334.  
  7335.                     subcnt = init->tnOp.tnOp2->tnIntCon.tnIconVal;
  7336.                 }
  7337.             }
  7338.             else
  7339.             {
  7340.                 cmpError(ERRbadBrNew, elem);
  7341.  
  7342.                 init = cmpCreateErrNode();
  7343.  
  7344.                 ourScanner->scanSkipText(tkLCurly, tkRCurly);
  7345.                 if  (ourScanner->scanTok.tok == tkRCurly)
  7346.                     ourScanner->scan();
  7347.             }
  7348.         }
  7349.         else
  7350.         {
  7351.             /* Can we accept an ordinary expression? */
  7352.  
  7353.             if  (dimPos)
  7354.                 init = cmpCreateErrNode(ERRnoLcurly);
  7355.             else
  7356.                 init = ourParser->parseExprComma();
  7357.  
  7358.             /* Bind the value and coerce it to the right type */
  7359.  
  7360.             init = cmpCoerceExpr(cmpBindExpr(init), elem, false);
  7361.         }
  7362.  
  7363.         /* Add the value to the list */
  7364.  
  7365.         list = ourParser->parseAddToNodeList(list, last, init);
  7366.         list->tnType = cmpTypeVoid;
  7367.         list->tnVtyp = TYP_VOID;
  7368.  
  7369.         /* Are there more initializers? */
  7370.  
  7371.         if  (ourScanner->scanTok.tok != tkComma)
  7372.             break;
  7373.  
  7374.         if  (ourScanner->scan() == tkRCurly)
  7375.             goto DONE;
  7376.     }
  7377.  
  7378.     if  (ourScanner->scanTok.tok != tkRCurly)
  7379.         cmpError(ERRnoCmRc);
  7380.  
  7381. DONE:
  7382.  
  7383.     // ISSUE: The following is not good enough for lots of dimensions!
  7384.  
  7385.     if  (elems != count && elems != 0 && dimPos)
  7386.         cmpGenError(ERRarrInitCnt, elems, count);
  7387.  
  7388.     ourScanner->scan();
  7389.  
  7390.     /* Stash the whole shebang (along with a count) under an array init node */
  7391.  
  7392.     return  cmpCreateExprNode(NULL,
  7393.                               TN_ARR_INIT,
  7394.                               type,
  7395.                               list,
  7396.                               cmpCreateIconNode(NULL, count, TYP_UINT));
  7397. }
  7398.  
  7399. /*****************************************************************************
  7400.  *
  7401.  *  Bind a {}-style array initializer.
  7402.  */
  7403.  
  7404. Tree                compiler::bindSLVinit(TypDef type, Tree init)
  7405. {
  7406.     parserState     save;
  7407.  
  7408.     /* This must be a managed array initializer */
  7409.  
  7410.     if  (type->tdTypeKind != TYP_ARRAY || !type->tdIsManaged)
  7411.     {
  7412.         cmpError(ERRbadBrNew, type);
  7413.         return  cmpCreateErrNode();
  7414.     }
  7415.  
  7416.     /* Start reading from the initializer's text */
  7417.  
  7418.     cmpParser->parsePrepText(&init->tnInit.tniSrcPos, init->tnInit.tniCompUnit, save);
  7419.  
  7420.     /* Parse and bind the initializer */
  7421.  
  7422.     init = cmpBindArrayExpr(type);
  7423.  
  7424.     /* We're done reading source text from the initializer */
  7425.  
  7426.     cmpParser->parseDoneText(save);
  7427.  
  7428.     return  init;
  7429. }
  7430.  
  7431. /*****************************************************************************
  7432.  *
  7433.  *  Bind a "new" expression.
  7434.  */
  7435.  
  7436. Tree                compiler::cmpBindNewExpr(Tree expr)
  7437. {
  7438.     TypDef          type;
  7439.     var_types       vtyp;
  7440.  
  7441.     Tree            init;
  7442.  
  7443.     assert(expr->tnOper == TN_NEW);
  7444.  
  7445.     /* Get hold of the initializer, if any */
  7446.  
  7447.     init = expr->tnOp.tnOp1;
  7448.  
  7449.     /* Check out the type and bind any expressions contained therein */
  7450.  
  7451.     type = expr->tnType;
  7452.     cmpBindType(type, true, (!init || init->tnOper != TN_SLV_INIT));
  7453.     vtyp = type->tdTypeKindGet();
  7454.  
  7455.     /* What kind of a value is the "new" trying to allocate? */
  7456.  
  7457.     switch (vtyp)
  7458.     {
  7459.         SymDef          clsSym;
  7460.  
  7461.     case TYP_CLASS:
  7462.  
  7463.         /* Make sure the type is a class not an interface */
  7464.  
  7465.         if  (type->tdClass.tdcFlavor == STF_INTF)
  7466.         {
  7467.             cmpError(ERRnewIntf, type);
  7468.             return cmpCreateErrNode();
  7469.         }
  7470.  
  7471.         /* Make sure the class is not abstract */
  7472.  
  7473.         clsSym = type->tdClass.tdcSymbol;
  7474.  
  7475.         if  (clsSym->sdIsAbstract)
  7476.         {
  7477.             cmpRecErrorPos(expr);
  7478.             cmpError(ERRnewAbstract, type);
  7479.             return cmpCreateErrNode();
  7480.         }
  7481.  
  7482.         /* See if the class is marked as "deprecated" */
  7483.  
  7484.         if  (clsSym->sdIsDeprecated)
  7485.             cmpObsoleteUse(clsSym, WRNdepCls);
  7486.  
  7487.         /* Is this a generic type argument ? */
  7488.  
  7489.         if  (clsSym->sdClass.sdcGenArg)
  7490.         {
  7491.             UNIMPL(!"sorry, 'new' on generic type argument NYI");
  7492.         }
  7493.  
  7494.         break;
  7495.  
  7496.     case TYP_ARRAY:
  7497.  
  7498.         /* Stash the true type under 'op2' */
  7499.  
  7500.         expr->tnOp.tnOp2 = cmpCreateExprNode(NULL, TN_NONE, type);
  7501.  
  7502.         /* Is this an unmanaged array? */
  7503.  
  7504.         if  (type->tdIsManaged)
  7505.             break;
  7506.  
  7507.         /* Switch to a pointer to the element type */
  7508.  
  7509.         vtyp = TYP_PTR;
  7510.         type = expr->tnType = cmpGlobalST->stNewRefType(vtyp, cmpDirectType(type->tdArr.tdaElem));
  7511.         break;
  7512.  
  7513.     case TYP_FNC:
  7514.     case TYP_VOID:
  7515.  
  7516.         cmpError(ERRbadNewTyp, type);
  7517.         return cmpCreateErrNode();
  7518.  
  7519.     default:
  7520.  
  7521.         if  (vtyp < TYP_lastIntrins)
  7522.         {
  7523.             type = cmpFindStdValType(vtyp); assert(type);
  7524.             vtyp = TYP_CLASS;
  7525.         }
  7526.         else
  7527.         {
  7528.             if  (!init)
  7529.             {
  7530.                 if  (vtyp == TYP_PTR)
  7531.                     type = type->tdRef.tdrBase;
  7532.  
  7533.                 cmpError(ERRnewNoVal, type);
  7534.                 return cmpCreateErrNode();
  7535.             }
  7536.         }
  7537.  
  7538.         break;
  7539.     }
  7540.  
  7541.     /* Is this a class or is there an initializer? */
  7542.  
  7543.     if  (vtyp == TYP_CLASS || init)
  7544.     {
  7545.         /* Bind the initializer, if present */
  7546.  
  7547.         if  (init)
  7548.         {
  7549.             if  (init->tnOper == TN_SLV_INIT)
  7550.             {
  7551.                 init = bindSLVinit(type, init);
  7552.  
  7553.                 expr->tnOp.tnOp1 = init;
  7554.  
  7555.                 expr->tnVtyp     = vtyp;
  7556.                 expr->tnType     = type;
  7557.  
  7558.                 return  expr;
  7559.             }
  7560.  
  7561.             init = cmpBindExpr(init);
  7562.  
  7563.             if  (init->tnVtyp == TYP_UNDEF)
  7564.                 return init;
  7565.         }
  7566.  
  7567.         /* Is this a class? */
  7568.  
  7569.         if  (vtyp == TYP_CLASS)
  7570.         {
  7571.             var_types       intr = (var_types)type->tdClass.tdcIntrType;
  7572.  
  7573.             if  (intr != TYP_UNDEF)
  7574.             {
  7575.                 /* The silly things people do ... */
  7576.  
  7577.                 if  (init)
  7578.                 {
  7579.                     assert(init->tnOper == TN_LIST);
  7580.  
  7581.                     if  (init->tnOp.tnOp2 == NULL)
  7582.                     {
  7583.                         /* We have something like "new Int32(val)" */
  7584.  
  7585.                         init = cmpCoerceExpr(init->tnOp.tnOp1,
  7586.                                              cmpGlobalST->stIntrinsicType(intr),
  7587.                                              false);
  7588.  
  7589.                         return  init;
  7590.                     }
  7591.                 }
  7592.             }
  7593.  
  7594.             expr = cmpCallCtor(type, init);
  7595.             if  (!expr)
  7596.             {
  7597.                 assert(type && type->tdTypeKind == TYP_CLASS);
  7598.  
  7599.                 cmpErrorXtp(ERRnoCtorMatch, type->tdClass.tdcSymbol, init);
  7600.                 return  cmpCreateErrNode();
  7601.             }
  7602.  
  7603.             return  expr;
  7604.         }
  7605.         else
  7606.         {
  7607.             /* Arrays can't be initialized - enforced by parser */
  7608.  
  7609.             assert(vtyp != TYP_ARRAY);
  7610.  
  7611.             /* Coerce the initializer to the expected type */
  7612.  
  7613.             expr->tnOp.tnOp2 = cmpCoerceExpr(init, type, false);
  7614.         }
  7615.     }
  7616.  
  7617.     expr->tnVtyp = vtyp;
  7618.  
  7619.     return  expr;
  7620. };
  7621.  
  7622. /*****************************************************************************
  7623.  *
  7624.  *  Add the next sub-operand to a concatenation (recursive).
  7625.  */
  7626.  
  7627. Tree                compiler::cmpAdd2Concat(Tree expr, Tree  list,
  7628.                                                        Tree *lastPtr)
  7629. {
  7630.     if  (expr->tnOper == TN_CONCAT || expr->tnOper == TN_ASG_CNC)
  7631.     {
  7632.         list = cmpAdd2Concat(expr->tnOp.tnOp1, list, lastPtr);
  7633.         list = cmpAdd2Concat(expr->tnOp.tnOp2, list, lastPtr);
  7634.     }
  7635.     else
  7636.     {
  7637.         Tree            addx;
  7638.  
  7639.         addx = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, expr, NULL);
  7640.  
  7641.         if  (list)
  7642.         {
  7643.             Tree            last = *lastPtr;
  7644.  
  7645.             assert(last && last->tnOper == TN_LIST
  7646.                         && last->tnOp.tnOp2 == NULL);
  7647.  
  7648.             last->tnOp.tnOp2 = addx;
  7649.         }
  7650.         else
  7651.         {
  7652.             list = addx;
  7653.         }
  7654.  
  7655.         *lastPtr = addx;
  7656.     }
  7657.  
  7658.     return  list;
  7659. }
  7660.  
  7661. /*****************************************************************************
  7662.  *
  7663.  *  Check the given unbound expression tree for string concatenation (this is
  7664.  *  done recursively). If the expression is a string concatenation, the tree
  7665.  *  will have the TN_CONCAT operator at the top.
  7666.  */
  7667.  
  7668. Tree                compiler::cmpListConcat(Tree expr)
  7669. {
  7670.     Tree            op1 = expr->tnOp.tnOp1;
  7671.     Tree            op2 = expr->tnOp.tnOp2;
  7672.  
  7673.     /* Special case: a '+=' node means "op1" is bound and known to be string */
  7674.  
  7675.     if  (expr->tnOper == TN_ASG_ADD)
  7676.          expr->tnOper =  TN_ASG_CNC;
  7677.  
  7678.     if  (expr->tnOper == TN_ASG_CNC)
  7679.     {
  7680.         assert(cmpIsStringExpr(op1));
  7681.         assert(op1->tnType == cmpRefTpString);
  7682.  
  7683.         goto BIND_OP2;
  7684.     }
  7685.  
  7686.     assert(expr->tnOper == TN_CONCAT ||
  7687.            expr->tnOper == TN_ADD);
  7688.  
  7689.     /* Bind both operands and see if either is a string */
  7690.  
  7691.     if  (op1->tnOper == TN_CONCAT || op1->tnOper == TN_ADD)
  7692.         op1 = cmpListConcat(op1);
  7693.     else
  7694.         op1 = cmpBindExprRec(op1);
  7695.  
  7696. BIND_OP2:
  7697.  
  7698.     if  (op2->tnOper == TN_CONCAT || op2->tnOper == TN_ADD)
  7699.         op2 = cmpListConcat(op2);
  7700.     else
  7701.         op2 = cmpBindExprRec(op2);
  7702.  
  7703.     expr->tnOp.tnOp1 = op1;
  7704.     expr->tnOp.tnOp2 = op2;
  7705.  
  7706.     if  (cmpIsStringExpr(op1) || cmpIsStringExpr(op2))
  7707.     {
  7708.         /* The concatenation operation will be bound in the second pass */
  7709.  
  7710.         if  (expr->tnOper != TN_ASG_CNC)
  7711.             expr->tnOper = TN_CONCAT;
  7712.  
  7713.         expr->tnType = cmpRefTpString;
  7714.         expr->tnVtyp = TYP_REF;
  7715.     }
  7716.     else
  7717.     {
  7718.         assert(expr->tnOper == TN_ADD);
  7719.  
  7720.         /* Rebind the expression, but not its operands */
  7721.  
  7722.         expr->tnFlags |= TNF_ADD_NOCAT;
  7723.  
  7724.         expr = cmpBindExprRec(expr);
  7725.     }
  7726.  
  7727.     return  expr;
  7728. }
  7729.  
  7730. /*****************************************************************************
  7731.  *
  7732.  *  Bind the given expression tree which may (but may not) denote string
  7733.  *  concatenation.
  7734.  */
  7735.  
  7736. Tree                compiler::cmpBindConcat(Tree expr)
  7737. {
  7738.     unsigned        ccnt;
  7739.  
  7740.     SymDef          cSym;
  7741.     bool            asgOp;
  7742.     bool            skip;
  7743.  
  7744.     Tree            last;
  7745.     Tree            list;
  7746.     Tree            temp;
  7747.  
  7748.     /* Process the expression, looking for string concatenation */
  7749.  
  7750.     list = cmpListConcat(expr);
  7751.  
  7752.     /* Check whether we have string concatenation / assignment or not */
  7753.  
  7754.     if      (list->tnOper == TN_CONCAT)
  7755.     {
  7756.         asgOp = false;
  7757.     }
  7758.     else if (list->tnOper == TN_ASG_CNC)
  7759.     {
  7760.         asgOp =  true;
  7761.     }
  7762.     else
  7763.         return  list;
  7764.  
  7765.     /* Create the list of all the operands we'll concatenate */
  7766.  
  7767.     last = NULL;
  7768.     list = cmpAdd2Concat(list, NULL, &last);
  7769.  
  7770.     /*
  7771.         We walk the list of concatenands twice - the first time we fold any
  7772.         adjacent constant strings, create a simple TN_LIST string of values
  7773.         and count the actual number of strings being concatenated. Then we
  7774.         decide how to achieve the concatenation: whether to call one of the
  7775.         Concat methods that take multiple strings or the String[] flavor.
  7776.      */
  7777.  
  7778.     ccnt = 0;
  7779.     temp = list;
  7780.     skip = asgOp;
  7781.  
  7782.     do
  7783.     {
  7784.         Tree            lstx;
  7785.         Tree            strx;
  7786.  
  7787.         /* Pull the next entry from the list */
  7788.  
  7789.         assert(temp && temp->tnOper == TN_LIST);
  7790.  
  7791.         lstx = temp;
  7792.         temp = temp->tnOp.tnOp2;
  7793.  
  7794.         /* Skip the first operand of an assignment operator */
  7795.  
  7796.         if  (skip)
  7797.         {
  7798.             assert(asgOp);
  7799.             skip = false;
  7800.  
  7801.             goto NEXT;
  7802.         }
  7803.  
  7804.         /* Grab the next operand's value */
  7805.  
  7806.         strx = lstx->tnOp.tnOp1;
  7807.  
  7808.         /* Is the operand a string constant and is there another operand? */
  7809.  
  7810.         if  (strx->tnOper == TN_CNS_STR && !(strx->tnFlags & TNF_BEEN_CAST) && strx->tnType == cmpStringRef() && temp)
  7811.         {
  7812.             for (;;)
  7813.             {
  7814.                 Tree            nxtx = temp->tnOp.tnOp1;
  7815.  
  7816.                 const   char *  str1;
  7817.                 size_t          len1;
  7818.                 const   char *  str2;
  7819.                 size_t          len2;
  7820.                         char *  strn;
  7821.                 size_t          lenn;
  7822.  
  7823.                 /* Is the next operand also a string constant? */
  7824.  
  7825.                 if  (nxtx->tnOper != TN_CNS_STR)
  7826.                     break;
  7827.  
  7828.                 /* Get hold of info for both strings */
  7829.  
  7830.                 str1 = strx->tnStrCon.tnSconVal;
  7831.                 len1 = strx->tnStrCon.tnSconLen;
  7832.                 str2 = nxtx->tnStrCon.tnSconVal;
  7833.                 len2 = nxtx->tnStrCon.tnSconLen;
  7834.  
  7835.                 /* Replace the first operand with the concatenated string */
  7836.  
  7837.                 lenn = len1 + len2;
  7838.                 strn = (char *)cmpAllocCGen.nraAlloc(roundUp(lenn+1));
  7839.                 memcpy(strn     , str1, len1);
  7840.                 memcpy(strn+len1, str2, len2+1);
  7841.  
  7842.                 strx->tnStrCon.tnSconVal = strn;
  7843.                 strx->tnStrCon.tnSconLen = lenn;
  7844.  
  7845.                 /* We've consumed the second operand, skip over it */
  7846.  
  7847.                 lstx->tnOp.tnOp2 = temp = temp->tnOp.tnOp2;
  7848.  
  7849.                 /* Any more operands to consider? */
  7850.  
  7851.                 if  (temp == NULL)
  7852.                 {
  7853.                     /* Is this all there is to it? */
  7854.  
  7855.                     if  (ccnt == 0)
  7856.                     {
  7857.                         assert(asgOp == false); // that would be truly amazing!
  7858.  
  7859.                         /* Neat - the whole thing folded into one string */
  7860.  
  7861.                         return  strx;
  7862.                     }
  7863.  
  7864.                     break;
  7865.                 }
  7866.             }
  7867.         }
  7868.         else
  7869.         {
  7870.             /* Make sure the operand is a string */
  7871.  
  7872.         CHK_STR:
  7873.  
  7874.             if  (strx->tnType != cmpStringRef())
  7875.             {
  7876.                 Tree            mksx;
  7877.                 SymDef          asym;
  7878.  
  7879.                 TypDef          type;
  7880.                 TypDef          btyp;
  7881.                 var_types       vtyp;
  7882.  
  7883.                 /* If the operand is a class, look for a "ToString" method */
  7884.  
  7885.                 type = strx->tnType;
  7886.                 vtyp = strx->tnVtypGet();
  7887.  
  7888.             RETRY:
  7889.  
  7890.                 switch (vtyp)
  7891.                 {
  7892.                 case TYP_REF:
  7893.  
  7894.                     btyp = cmpActualType(type->tdRef.tdrBase);
  7895.                     if  (btyp->tdTypeKind != TYP_CLASS)
  7896.                     {
  7897.                         /* We have two choices: report an error or use the referenced value */
  7898.  
  7899. #if 0
  7900.                         goto CAT_ERR;
  7901. #else
  7902.                         strx = cmpCreateExprNode(NULL, TN_IND, btyp, strx, NULL);
  7903.                         goto CHK_STR;
  7904. #endif
  7905.                     }
  7906.  
  7907.                     type = btyp;
  7908.                     goto CLSR;
  7909.  
  7910.                 case TYP_CLASS:
  7911.  
  7912.                     if  (type->tdIsManaged)
  7913.                     {
  7914.                     CLSR:
  7915.                         asym = cmpGlobalST->stLookupAllCls(cmpIdentToString,
  7916.                                                            type->tdClass.tdcSymbol,
  7917.                                                            NS_NORM,
  7918.                                                            CS_DECLSOON);
  7919.                         if  (asym)
  7920.                         {
  7921.                             asym = cmpFindOvlMatch(asym, NULL, NULL);
  7922.                             if  (asym)
  7923.                             {
  7924.                                 if  (vtyp == TYP_REF)
  7925.                                     goto CALL;
  7926.                                 if  (asym->sdParent != cmpClassObject)
  7927.                                     goto ADDR;
  7928.  
  7929.                             }
  7930.                         }
  7931.  
  7932.                         assert(vtyp != TYP_REF);
  7933.  
  7934.                         /* Box the thing and use Object.toString() on it */
  7935.  
  7936.                         strx = cmpCreateExprNode(NULL, TN_BOX, cmpRefTpObject, strx);
  7937.                         type = cmpClassObject->sdType;
  7938.  
  7939.                         goto CLST;
  7940.                     }
  7941.  
  7942.                     // Fall through ...
  7943.  
  7944.                 case TYP_FNC:
  7945.                 case TYP_PTR:
  7946.  
  7947.                 CAT_ERR:
  7948.  
  7949.                     cmpError(ERRbadConcat, type);
  7950.                     goto NEXT;
  7951.  
  7952.                 case TYP_ARRAY:
  7953.  
  7954.                     /* If the array is managed, simply call "Object.ToString" on it */
  7955.  
  7956.                     if  (type->tdIsManaged)
  7957.                     {
  7958.                         type = cmpRefTpObject;
  7959.                         vtyp = TYP_REF;
  7960.                         goto RETRY;
  7961.                     }
  7962.  
  7963.                     goto CAT_ERR;
  7964.  
  7965.                 case TYP_ENUM:
  7966.  
  7967.                     cmpWarn(WRNenum2str, type);
  7968.  
  7969.                     type = type->tdEnum.tdeIntType;
  7970.                     vtyp = type->tdTypeKindGet();
  7971.                     goto RETRY;
  7972.  
  7973.                 case TYP_UNDEF:
  7974.                     return  strx;
  7975.                 }
  7976.  
  7977.                 /* Bash the value to be the equivalent struct and call Object.ToString on it */
  7978.  
  7979.                 assert(vtyp <= TYP_lastIntrins);
  7980.  
  7981.                 /* Locate the appropriate built-in value type */
  7982.  
  7983.                 type = cmpFindStdValType(vtyp);
  7984.                 if  (!type)
  7985.                     goto CAT_ERR;
  7986.  
  7987.             CLST:
  7988.  
  7989.                 asym = cmpGlobalST->stLookupClsSym(cmpIdentToString, type->tdClass.tdcSymbol);
  7990.                 if  (!asym)
  7991.                     goto CAT_ERR;
  7992.                 asym = cmpFindOvlMatch(asym, NULL, NULL);
  7993.                 if  (!asym)
  7994.                     goto CAT_ERR;
  7995.  
  7996.             ADDR:
  7997.  
  7998.                 assert(type->tdTypeKind == TYP_CLASS);
  7999.  
  8000.                 /* Take the address of the thing so that we can call ToString() */
  8001.  
  8002.                 if  (strx->tnOper != TN_BOX)
  8003.                 {
  8004.                     strx = cmpCreateExprNode(NULL,
  8005.                                              TN_ADDROF,
  8006.                                              type->tdClass.tdcRefTyp,
  8007.                                              strx,
  8008.                                              NULL);
  8009.                 }
  8010.  
  8011.             CALL:
  8012.  
  8013.                 // UNDONE: Check that ToString is not static
  8014.  
  8015.                 lstx->tnOp.tnOp1 = mksx  = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpRefTpString);
  8016.                 mksx->tnFncSym.tnFncSym  = asym;
  8017.                 mksx->tnFncSym.tnFncArgs = NULL;
  8018.                 mksx->tnFncSym.tnFncObj  = strx;
  8019.                 mksx->tnFncSym.tnFncScp  = NULL;
  8020.  
  8021.                 if  (strx->tnOper == TN_ADDROF)
  8022.                     mksx->tnFlags |= TNF_CALL_NVIRT;
  8023.             }
  8024.         }
  8025.  
  8026.     NEXT:
  8027.  
  8028.         ccnt++;
  8029.     }
  8030.     while (temp);
  8031.  
  8032.     assert(ccnt > 1);
  8033.  
  8034.     if  (!cmpIdentConcat)
  8035.         cmpIdentConcat = cmpGlobalHT->hashString("Concat");
  8036.  
  8037.     /* Do we have 2-3 or more operands? */
  8038.  
  8039.     if  (ccnt <= 3)
  8040.     {
  8041.         ArgDscRec       args;
  8042.         TypDef          type;
  8043.  
  8044.         /* Just a few operands, let's call the multi-string Concat method */
  8045.  
  8046.         if  (ccnt == 2)
  8047.         {
  8048.             cSym = cmpConcStr2Fnc;
  8049.             if  (cSym)
  8050.                 goto CALL_CTOR;
  8051.  
  8052.             cmpParser->parseArgListNew(args,
  8053.                                        2,
  8054.                                        false, cmpRefTpString,
  8055.                                               cmpRefTpString,
  8056.                                               NULL);
  8057.         }
  8058.         else
  8059.         {
  8060.             cSym = cmpConcStr3Fnc;
  8061.             if  (cSym)
  8062.                 goto CALL_CTOR;
  8063.  
  8064.             cmpParser->parseArgListNew(args,
  8065.                                        3,
  8066.                                        false, cmpRefTpString,
  8067.                                               cmpRefTpString,
  8068.                                               cmpRefTpString,
  8069.                                               NULL);
  8070.         }
  8071.  
  8072.         /* Find the appropriate String constructor */
  8073.  
  8074.         type = cmpGlobalST->stNewFncType(args, cmpTypeVoid);
  8075.         cSym = cmpGlobalST->stLookupClsSym(cmpIdentConcat, cmpClassString); assert(cSym);
  8076.         cSym = cmpCurST->stFindOvlFnc(cSym, type); assert(cSym);
  8077.  
  8078.         if  (ccnt == 2)
  8079.             cmpConcStr2Fnc = cSym;
  8080.         else
  8081.             cmpConcStr3Fnc = cSym;
  8082.  
  8083.     CALL_CTOR:
  8084.  
  8085.         /* Create the call to the constructor */
  8086.  
  8087.         last = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpRefTpString);
  8088.         last->tnFncSym.tnFncSym  = cSym;
  8089.         last->tnFncSym.tnFncArgs = list;
  8090.         last->tnFncSym.tnFncObj  = NULL;
  8091.         last->tnFncSym.tnFncScp  = NULL;
  8092.     }
  8093.     else
  8094.     {
  8095.         /* Lots of operands, call the String[] operator */
  8096.  
  8097.         if  (!cmpConcStrAFnc)
  8098.         {
  8099.             ArgDscRec       args;
  8100.             TypDef          type;
  8101.  
  8102.             /* Create the type "void func(String [])" */
  8103.  
  8104.             if  (!cmpTypeStrArr)
  8105.             {
  8106.                 DimDef          dims = cmpGlobalST->stNewDimDesc(0);
  8107.  
  8108.                 cmpTypeStrArr = cmpGlobalST->stNewArrType(dims, true, cmpRefTpString);
  8109.             }
  8110.  
  8111.             cmpParser->parseArgListNew(args, 1, false, cmpTypeStrArr, NULL);
  8112.  
  8113.             /* Find the appropriate String constructor */
  8114.  
  8115.             type  = cmpGlobalST->stNewFncType(args, cmpTypeVoid);
  8116.             cSym = cmpGlobalST->stLookupClsSym(cmpIdentConcat, cmpClassString); assert(cSym);
  8117.             cSym = cmpCurST->stFindOvlFnc(cSym, type); assert(cSym);
  8118.  
  8119.             cmpConcStrAFnc = cSym;
  8120.         }
  8121.  
  8122.         /* Create the array initializer expression and pass it to the ctor */
  8123.  
  8124.         list = cmpCreateExprNode(NULL,
  8125.                                  TN_ARR_INIT,
  8126.                                  cmpTypeStrArr,
  8127.                                  list,
  8128.                                  cmpCreateIconNode(NULL, ccnt, TYP_UINT));
  8129.  
  8130.         list = cmpCreateExprNode(NULL, TN_NEW , cmpTypeStrArr, list);
  8131.         list = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid  , list);
  8132.  
  8133.         last = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpRefTpString);
  8134.         last->tnFncSym.tnFncSym  = cmpConcStrAFnc;
  8135.         last->tnFncSym.tnFncArgs = list;
  8136.         last->tnFncSym.tnFncObj  = NULL;
  8137.         last->tnFncSym.tnFncScp  = NULL;
  8138.     }
  8139.  
  8140.     assert(last->tnOper == TN_FNC_SYM);
  8141.  
  8142.     /* Mark the call if this is an assignment operator */
  8143.  
  8144.     if  (asgOp)
  8145.         last->tnFlags |= TNF_CALL_STRCAT;
  8146.  
  8147.     /* Wrap the ctor call in a "new" node and we're done */
  8148.  
  8149.     return  last;
  8150. }
  8151.  
  8152. /*****************************************************************************
  8153.  *
  8154.  *  Bind a ?: expression.
  8155.  */
  8156.  
  8157. Tree                compiler::cmpBindQmarkExpr(Tree expr)
  8158. {
  8159.     Tree            op1;
  8160.     Tree            op2;
  8161.  
  8162.     var_types       tp1;
  8163.     var_types       tp2;
  8164.  
  8165.     var_types       bt1;
  8166.     var_types       bt2;
  8167.  
  8168.     /* The parser should make sure that the ":" operator is present */
  8169.  
  8170.     assert(expr->tnOper == TN_QMARK);
  8171.     assert(expr->tnOp.tnOp2->tnOper == TN_COLON);
  8172.  
  8173.     /* Bind the condition */
  8174.  
  8175.     expr->tnOp.tnOp1 = cmpBindCondition(expr->tnOp.tnOp1);
  8176.  
  8177.     /* Get hold of the two ":" values */
  8178.  
  8179.     op1 = expr->tnOp.tnOp2->tnOp.tnOp1;
  8180.     op2 = expr->tnOp.tnOp2->tnOp.tnOp2;
  8181.  
  8182.     /* Special case: is either operand a string constant? */
  8183.  
  8184.     if      (op1->tnOper == TN_CNS_STR && !(op1->tnFlags & TNF_BEEN_CAST))
  8185.     {
  8186.         if      (op2->tnOper == TN_CNS_STR && !(op2->tnFlags & TNF_BEEN_CAST))
  8187.         {
  8188.  
  8189. #if 0
  8190.  
  8191.             if  (op1->tnType == op2->tnType)
  8192.             {
  8193.                 expr->tnType = op1->tnType;
  8194.                 expr->tnVtyp = op1->tnVtyp;
  8195.  
  8196.                 return  expr;
  8197.             }
  8198.  
  8199. #endif
  8200.  
  8201.             op1 = cmpBindExpr(op1);
  8202.             op2 = cmpBindExpr(op2);
  8203.         }
  8204.         else
  8205.         {
  8206.             op2 = cmpBindExpr(op2);
  8207.             op1 = cmpParser->parseCreateOperNode(TN_CAST, op1, NULL);
  8208.             op1->tnType = op2->tnType;
  8209.             op1 = cmpBindExpr(op1);
  8210.         }
  8211.     }
  8212.     else if (op2->tnOper == TN_CNS_STR && !(op2->tnFlags & TNF_BEEN_CAST))
  8213.     {
  8214.         op1 = cmpBindExpr(op1);
  8215.         op2 = cmpParser->parseCreateOperNode(TN_CAST, op2, NULL);
  8216.         op2->tnType = op1->tnType;
  8217.         op2 = cmpBindExpr(op2);
  8218.     }
  8219.     else
  8220.     {
  8221.         op1 = cmpBindExpr(op1);
  8222.         op2 = cmpBindExpr(op2);
  8223.     }
  8224.  
  8225.     /* Now see what the types of the operands are */
  8226.  
  8227.     tp1 = op1->tnVtypGet(); assert(tp1 != TYP_TYPEDEF);
  8228.     tp2 = op2->tnVtypGet(); assert(tp2 != TYP_TYPEDEF);
  8229.  
  8230.     /* The operands may be arithmetic */
  8231.  
  8232.     if  (varTypeIsArithmetic(tp1) &&
  8233.          varTypeIsArithmetic(tp2))
  8234.     {
  8235.         /* Shrink numeric constants if types are unequal */
  8236.  
  8237.         if  (tp1 != tp2)
  8238.         {
  8239.             op1 = cmpShrinkExpr(op1); tp1 = op1->tnVtypGet();
  8240.             op2 = cmpShrinkExpr(op2); tp2 = op2->tnVtypGet();
  8241.         }
  8242.  
  8243.     PROMOTE:
  8244.  
  8245.         /* Promote both operands to the 'bigger' type */
  8246.  
  8247.         if      (tp1 < tp2)
  8248.         {
  8249.             op1 = cmpCoerceExpr(op1, op2->tnType, false);
  8250.         }
  8251.         else if (tp1 > tp2)
  8252.         {
  8253.             op2 = cmpCoerceExpr(op2, op1->tnType, false);
  8254.         }
  8255.  
  8256.         goto GOT_QM;
  8257.     }
  8258.  
  8259.     /* The operands can be pointers/refs */
  8260.  
  8261.     if  ((tp1 == TYP_REF || tp1 == TYP_PTR) &&
  8262.          (tp2 == TYP_REF || tp2 == TYP_PTR))
  8263.     {
  8264.         /* It's perfectly fine if one of the operands is "null" */
  8265.  
  8266.         if      (op2->tnOper == TN_NULL)
  8267.         {
  8268.             op2 = cmpCoerceExpr(op2, op1->tnType, false);
  8269.             goto GOT_QM;
  8270.         }
  8271.         else if (op1->tnOper == TN_NULL)
  8272.         {
  8273.             op1 = cmpCoerceExpr(op1, op2->tnType, false);
  8274.             goto GOT_QM;
  8275.         }
  8276.  
  8277.         /* Are both things of the same flavor? */
  8278.  
  8279.         if  (tp1 == tp2)
  8280.         {
  8281.             if  (cmpConvergeValues(op1, op2))
  8282.                 goto GOT_QM;
  8283.         }
  8284.         else
  8285.         {
  8286.             /* Special case: string literals can become "char *" */
  8287.  
  8288.             if  (tp1 == TYP_PTR && tp2 == TYP_REF)
  8289.             {
  8290.                 if  (cmpMakeRawString(op2, op1->tnType))
  8291.                     goto GOT_QM;
  8292.             }
  8293.             else
  8294.             {
  8295.                 if  (cmpMakeRawString(op1, op2->tnType))
  8296.                     goto GOT_QM;
  8297.             }
  8298.         }
  8299.     }
  8300.  
  8301.     /* Both operands can be arrays */
  8302.  
  8303.     if  (tp1 == TYP_ARRAY)
  8304.     {
  8305.         if  (cmpIsObjectVal(op2))
  8306.         {
  8307.             if  (op2->tnOper == TN_NULL)
  8308.                 op2 = cmpCoerceExpr(op2, op1->tnType, false);
  8309.             else
  8310.                 op1 = cmpCoerceExpr(op1, op2->tnType, false);
  8311.  
  8312.             goto GOT_QM;
  8313.         }
  8314.  
  8315.         if  (tp2 == TYP_ARRAY)
  8316.         {
  8317.             // UNDONE: compare array types!
  8318.         }
  8319.     }
  8320.  
  8321.     if  (tp2 == TYP_ARRAY)
  8322.     {
  8323.         if  (cmpIsObjectVal(op1))
  8324.         {
  8325.             if  (op1->tnOper == TN_NULL)
  8326.                 op1 = cmpCoerceExpr(op1, op2->tnType, false);
  8327.             else
  8328.                 op2 = cmpCoerceExpr(op2, op1->tnType, false);
  8329.  
  8330.             goto GOT_QM;
  8331.         }
  8332.     }
  8333.  
  8334.     /* If both operands have identical type, it's easy */
  8335.  
  8336.     if  (tp1 == tp2 && symTab::stMatchTypes(op1->tnType, op2->tnType))
  8337.         goto GOT_QM;
  8338.  
  8339.     /* We could also have enums, of course */
  8340.  
  8341.     if      (tp1 == TYP_ENUM)
  8342.     {
  8343.         TypDef          typ;
  8344.  
  8345.         /* Are both of these enums? */
  8346.  
  8347.         if  (tp2 == TYP_ENUM)
  8348.         {
  8349.             bt2 = cmpActualVtyp(op2->tnType);
  8350.         }
  8351.         else
  8352.         {
  8353.             if  (!varTypeIsArithmetic(tp2))
  8354.                 goto ENUMN;
  8355.  
  8356.             bt2 = tp2;
  8357.         }
  8358.  
  8359.         bt1 = cmpActualVtyp(op1->tnType);
  8360.  
  8361.     ENUMP:
  8362.  
  8363.         /* Promote to whichever is the larger type, or int */
  8364.  
  8365.         assert(bt1 != TYP_ENUM);
  8366.         assert(bt2 != TYP_ENUM);
  8367.  
  8368.         if  (bt1 < bt2)
  8369.              bt1 = bt2;
  8370.         if  (bt1 < TYP_INT)
  8371.              bt1 = TYP_INT;
  8372.  
  8373.         typ = cmpGlobalST->stIntrinsicType(bt1);
  8374.  
  8375.         op1 = cmpCoerceExpr(op1, typ, false);
  8376.         op2 = cmpCoerceExpr(op2, typ, false);
  8377.  
  8378.         goto GOT_QM;
  8379.     }
  8380.     else if (tp2 == TYP_ENUM)
  8381.     {
  8382.         if  (varTypeIsArithmetic(tp1))
  8383.         {
  8384.             bt1 = tp1;
  8385.             bt2 = cmpActualVtyp(op2->tnType);
  8386.  
  8387.             goto ENUMP;
  8388.         }
  8389.     }
  8390.  
  8391. ENUMN:
  8392.  
  8393.     /* Mixing bools/wchars and arithmetic types is OK as well */
  8394.  
  8395.     if  (varTypeIsArithmetic(tp1) && (tp2 == TYP_BOOL || tp2 == TYP_WCHAR))
  8396.         goto PROMOTE;
  8397.     if  (varTypeIsArithmetic(tp2) && (tp1 == TYP_BOOL || tp1 == TYP_WCHAR))
  8398.         goto PROMOTE;
  8399.  
  8400.     /* There are no more legal ":" operand types */
  8401.  
  8402.     cmpRecErrorPos(expr);
  8403.  
  8404.     if  (tp1 != TYP_UNDEF && tp2 != TYP_UNDEF)
  8405.         cmpError(ERRoperType2, cmpGlobalHT->tokenToIdent(tkQMark), op1->tnType, op2->tnType);
  8406.  
  8407.     return cmpCreateErrNode();
  8408.  
  8409. GOT_QM:
  8410.  
  8411.     /* Everything's fine, create the ":" node */
  8412.  
  8413.     assert(symTab::stMatchTypes(op1->tnType, op2->tnType));
  8414.  
  8415.     expr->tnOp.tnOp2 = cmpCreateExprNode(expr->tnOp.tnOp2,
  8416.                                          TN_COLON,
  8417.                                          op1->tnType,
  8418.                                          op1,
  8419.                                          op2);
  8420.  
  8421.     /* The result is the type of (both of) the operands */
  8422.  
  8423.     expr->tnVtyp = op1->tnVtyp;
  8424.     expr->tnType = op1->tnType;
  8425.  
  8426.     return  expr;
  8427. }
  8428.  
  8429. /*****************************************************************************
  8430.  *
  8431.  *  Given an expression and a type (at least one of which is known to be
  8432.  *  a value type) see if there is an overloaded conversion operator that
  8433.  *  can convert the expression to the target type. If the conversion is
  8434.  *  not possible, NULL is returned. Otherwise, if 'origTP' on entry is
  8435.  *  non-NULL, a converted expression is converted, else the expression
  8436.  *  is returned untouched (this way the routine can be called just to
  8437.  *  see if the given conversion is possible).
  8438.  */
  8439.  
  8440. Tree                compiler::cmpCheckConvOper(Tree      expr,
  8441.                                                TypDef  origTP,
  8442.                                                TypDef dstType,
  8443.                                                bool   expConv, unsigned *costPtr)
  8444. {
  8445.     TypDef          srcType;
  8446.  
  8447.     var_types       srcVtyp;
  8448.     var_types       dstVtyp;
  8449.  
  8450.     SymDef          opSrcExp, opSrcImp;
  8451.     SymDef          opDstExp, opDstImp;
  8452.  
  8453.     unsigned        lowCost;
  8454.     SymDef          bestOp1;
  8455.     SymDef          bestOp2;
  8456.  
  8457.     /* Get hold of the source type */
  8458.  
  8459.     srcType = origTP;
  8460.     if  (!srcType)
  8461.     {
  8462.         assert(expr);
  8463.  
  8464.         srcType = expr->tnType;
  8465.  
  8466.         if  (srcType->tdTypeKind == TYP_TYPEDEF)
  8467.              srcType = srcType->tdTypedef.tdtType;
  8468.     }
  8469.  
  8470.     /* Make sure the destination type is the real thing */
  8471.  
  8472.     dstType = cmpDirectType(dstType);
  8473.  
  8474.     /* Either one or both of the types must be value types */
  8475.  
  8476.     srcVtyp = srcType->tdTypeKindGet();
  8477.     dstVtyp = dstType->tdTypeKindGet();
  8478.  
  8479.     assert(srcVtyp == TYP_CLASS || dstVtyp == TYP_CLASS);
  8480.  
  8481.     /* Find all the operators that might apply to this conversion */
  8482.  
  8483.     opSrcImp =
  8484.     opDstImp =
  8485.     opSrcExp =
  8486.     opDstExp = NULL;
  8487.  
  8488.     if  (srcVtyp == TYP_CLASS)
  8489.     {
  8490.         SymDef          srcCls = srcType->tdClass.tdcSymbol;
  8491.  
  8492.         opSrcImp = cmpGlobalST->stLookupOper(OVOP_CONV_IMP, srcCls);
  8493.         if  (expConv)
  8494.         opSrcExp = cmpGlobalST->stLookupOper(OVOP_CONV_EXP, srcCls);
  8495.     }
  8496.  
  8497.     if  (dstVtyp == TYP_CLASS)
  8498.     {
  8499.         SymDef          dstCls = dstType->tdClass.tdcSymbol;
  8500.  
  8501.         opDstImp = cmpGlobalST->stLookupOper(OVOP_CONV_IMP, dstCls);
  8502.         if  (expConv)
  8503.         opDstExp = cmpGlobalST->stLookupOper(OVOP_CONV_EXP, dstCls);
  8504.     }
  8505.  
  8506. #if 0
  8507.  
  8508.     printf("\nCheck user-defined conversion operator:\n");
  8509.  
  8510.     printf("   Src type = '%s'\n", cmpGlobalST->stTypeName(srcType, NULL, NULL, NULL, false));
  8511.     printf("   Dst type = '%s'\n", cmpGlobalST->stTypeName(dstType, NULL, NULL, NULL, false));
  8512.  
  8513.     printf("\n");
  8514.  
  8515.     if  (opSrcImp)
  8516.     {
  8517.         SymDef          sym;
  8518.         printf("opSrcImp:\n");
  8519.         for (sym = opSrcImp; sym; sym = sym->sdFnc.sdfNextOvl)
  8520.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8521.         printf("\n");
  8522.     }
  8523.  
  8524.     if  (opSrcExp)
  8525.     {
  8526.         SymDef          sym;
  8527.         printf("opSrcExp:\n");
  8528.         for (sym = opSrcExp; sym; sym = sym->sdFnc.sdfNextOvl)
  8529.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8530.         printf("\n");
  8531.     }
  8532.  
  8533.     if  (opDstImp)
  8534.     {
  8535.         SymDef          sym;
  8536.         printf("opDstImp:\n");
  8537.         for (sym = opDstImp; sym; sym = sym->sdFnc.sdfNextOvl)
  8538.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8539.         printf("\n");
  8540.     }
  8541.  
  8542.     if  (opDstExp)
  8543.     {
  8544.         SymDef          sym;
  8545.         printf("opDstExp:\n");
  8546.         for (sym = opDstExp; sym; sym = sym->sdFnc.sdfNextOvl)
  8547.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8548.         printf("\n");
  8549.     }
  8550.  
  8551. #endif
  8552.  
  8553.     /* Check all of the possible operators, looking for the best match */
  8554.  
  8555.     bestOp1 =
  8556.     bestOp2 = NULL;
  8557.     lowCost = 99999;
  8558.  
  8559.     if  (opSrcImp) lowCost = cmpMeasureConv(expr, dstType, lowCost, opSrcImp, &bestOp1, &bestOp2);
  8560.     if  (opDstImp) lowCost = cmpMeasureConv(expr, dstType, lowCost, opDstImp, &bestOp1, &bestOp2);
  8561.     if  (opSrcExp) lowCost = cmpMeasureConv(expr, dstType, lowCost, opSrcExp, &bestOp1, &bestOp2);
  8562.     if  (opDstExp) lowCost = cmpMeasureConv(expr, dstType, lowCost, opDstExp, &bestOp1, &bestOp2);
  8563.  
  8564.     /* If no conversion at all worked, return NULL */
  8565.  
  8566.     if  (bestOp1 == NULL)
  8567.     {
  8568.         assert(bestOp2 == NULL);
  8569.         return  NULL;
  8570.     }
  8571.  
  8572.     /* Is a simple boxing operation better than the best we've found? */
  8573.  
  8574.     if  (lowCost > 10 && dstType == cmpRefTpObject)
  8575.         return  cmpCreateExprNode(NULL, TN_BOX, dstType, expr);
  8576.  
  8577.     /* Did we end up with a clear winner? */
  8578.  
  8579.     if  (bestOp2 != NULL)
  8580.     {
  8581.         if  (origTP)
  8582.             return  NULL;
  8583.  
  8584.         cmpErrorQSS(ERRambigCall, bestOp1, bestOp2);
  8585.         return cmpCreateErrNode();
  8586.     }
  8587.  
  8588.     /* We have a single best match in "bestOp1" - are we supposed to call it? */
  8589.  
  8590.     if  (origTP == NULL)
  8591.     {
  8592.         ArgDef          argList;
  8593.         Tree            argExpr;
  8594.  
  8595.         assert(bestOp1->sdType->tdTypeKind == TYP_FNC);
  8596.  
  8597. //      printf("Calling conversion operator:\n\t%s\n", cmpGlobalST->stTypeName(bestOp1->sdType, bestOp1, NULL, NULL, true));
  8598.  
  8599.         /* Has the function been marked as "deprecated" ? */
  8600.  
  8601.         if  (bestOp1->sdIsDeprecated || bestOp1->sdParent->sdIsDeprecated)
  8602.         {
  8603.             if  (bestOp1->sdIsImport)
  8604.             {
  8605.                 if  (bestOp1->sdIsDeprecated)
  8606.                     cmpObsoleteUse(bestOp1          , WRNdepCall);
  8607.                 else
  8608.                     cmpObsoleteUse(bestOp1->sdParent, WRNdepCls);
  8609.             }
  8610.         }
  8611.  
  8612.         /* Get hold of the conversion's source and target type */
  8613.  
  8614.         argList = bestOp1->sdType->tdFnc.tdfArgs.adArgs;
  8615.  
  8616.         /* There should be exactly one parameter */
  8617.  
  8618.         assert(argList && argList->adNext == NULL);
  8619.  
  8620.         /* Coerce the expression to the argument type */
  8621.  
  8622.         argExpr = cmpCoerceExpr(expr, argList->adType, true);
  8623.         argExpr = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argExpr, NULL);
  8624.  
  8625.         /* Create the operator function call node */
  8626.  
  8627.         expr = cmpCreateExprNode(NULL, TN_FNC_SYM, bestOp1->sdType->tdFnc.tdfRett);
  8628.         expr->tnFncSym.tnFncSym  = bestOp1;
  8629.         expr->tnFncSym.tnFncArgs = argExpr;
  8630.         expr->tnFncSym.tnFncObj  = NULL;
  8631.         expr->tnFncSym.tnFncScp  = NULL;
  8632.  
  8633.         /* Finally, convert the result of the conversion to the target type */
  8634.  
  8635.         expr = cmpCoerceExpr(expr, dstType, true);
  8636.     }
  8637.  
  8638.     if  (costPtr) *costPtr = lowCost;
  8639.  
  8640.     return  expr;
  8641. }
  8642. /*****************************************************************************
  8643.  *
  8644.  *  Given an expression with at least one operator of type 'struct', see if
  8645.  *  there is an overloaded operator defined that can be called. Returns NULL
  8646.  *  if no luck, otherwise returns an expression that will yield the operator
  8647.  *  call.
  8648.  */
  8649.  
  8650. Tree                compiler::cmpCheckOvlOper(Tree expr)
  8651. {
  8652.     Tree            op1 = expr->tnOp.tnOp1;
  8653.     Tree            op2 = expr->tnOp.tnOp2;
  8654.  
  8655.     TypDef          op1Type;
  8656.     TypDef          op2Type;
  8657.  
  8658.     SymDef          op1Oper;
  8659.     SymDef          op2Oper;
  8660.  
  8661.     treeOps         oper;
  8662.     tokens          optok;
  8663.     ovlOpFlavors    opovl;
  8664.  
  8665.     Tree            arg1;
  8666.     Tree            arg2;
  8667.     Tree            call;
  8668.  
  8669.     /* Check to make sure the operator is overloadable */
  8670.  
  8671.     oper  = expr->tnOperGet();
  8672.     optok = treeOp2token(oper);
  8673.     opovl = cmpGlobalST->stOvlOperIndex(optok, (op2 != NULL) ? 2 : 1);
  8674.     if  (opovl == OVOP_NONE)
  8675.         return  NULL;
  8676.  
  8677.     /* Get hold of the two operand types */
  8678.  
  8679.     op1Type =       cmpDirectType(op1->tnType);
  8680.     op2Type = op2 ? cmpDirectType(op2->tnType) : cmpTypeVoid;
  8681.  
  8682.     /* Find all the operators that might apply to this operator */
  8683.  
  8684.     op1Oper =
  8685.     op2Oper = NULL;
  8686.  
  8687.     switch (op1Type->tdTypeKind)
  8688.     {
  8689.     case TYP_REF:
  8690.         op1Type = op1Type->tdRef.tdrBase;
  8691.         if  (op1Type->tdTypeKind != TYP_CLASS)
  8692.             break;
  8693.  
  8694.         // Fall through ...
  8695.  
  8696.     case TYP_CLASS:
  8697.         op1Oper = cmpGlobalST->stLookupOper(opovl, op1Type->tdClass.tdcSymbol);
  8698.         break;
  8699.     }
  8700.  
  8701.     switch (op2Type->tdTypeKind)
  8702.     {
  8703.     case TYP_REF:
  8704.         op2Type = op2Type->tdRef.tdrBase;
  8705.         if  (op2Type->tdTypeKind != TYP_CLASS)
  8706.             break;
  8707.  
  8708.         // Fall through ...
  8709.  
  8710.     case TYP_CLASS:
  8711.         op2Oper = cmpGlobalST->stLookupOper(opovl, op2Type->tdClass.tdcSymbol);
  8712.         break;
  8713.     }
  8714.  
  8715.     if  (op1Oper == NULL && op2Oper == NULL)
  8716.         return  NULL;
  8717.  
  8718.     if  (op2Oper == op1Oper)
  8719.          op2Oper = NULL;
  8720.  
  8721. #if 0
  8722.  
  8723.     printf("\nCheck user-defined overloaded operator:\n");
  8724.  
  8725.     printf("   op1 type = '%s'\n", cmpGlobalST->stTypeName(op1Type, NULL, NULL, NULL, false));
  8726.     printf("   op2 type = '%s'\n", cmpGlobalST->stTypeName(op2Type, NULL, NULL, NULL, false));
  8727.  
  8728.     printf("\n");
  8729.  
  8730.     if  (op1Oper)
  8731.     {
  8732.         SymDef          sym;
  8733.         printf("op1Oper:\n");
  8734.         for (sym = op1Oper; sym; sym = sym->sdFnc.sdfNextOvl)
  8735.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8736.         printf("\n");
  8737.     }
  8738.  
  8739.     if  (op2Oper)
  8740.     {
  8741.         SymDef          sym;
  8742.         printf("op2Oper:\n");
  8743.         for (sym = op2Oper; sym; sym = sym->sdFnc.sdfNextOvl)
  8744.             printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8745.         printf("\n");
  8746.     }
  8747.  
  8748. #endif
  8749.  
  8750.     /* Create an argument list tree so that we can try to bind the call */
  8751.  
  8752.     arg2 = op2 ? cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, op2, NULL) : NULL;
  8753.     arg1 =       cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, op1, arg2);
  8754.  
  8755.     call = cmpCreateExprNode(expr, TN_FNC_SYM, cmpTypeVoid);
  8756.     call->tnFlags |= TNF_CALL_CHKOVL;
  8757.  
  8758.     call->tnFncSym.tnFncArgs = arg1;
  8759.     call->tnFncSym.tnFncObj  = NULL;
  8760.     call->tnFncSym.tnFncScp  = NULL;
  8761.  
  8762.     if  (op1Oper)
  8763.     {
  8764.         if  (op2Oper)
  8765.         {
  8766.             UNIMPL(!"NYI: two sets of overloaded operators to consider");
  8767.         }
  8768.         else
  8769.             call->tnFncSym.tnFncSym  = op1Oper;
  8770.     }
  8771.     else
  8772.         call->tnFncSym.tnFncSym  = op2Oper;
  8773.  
  8774.     call = cmpCheckFuncCall(call);
  8775.  
  8776.     /* Increment/decrement operators require special handling */
  8777.  
  8778.     switch (oper)
  8779.     {
  8780.     case TN_INC_PRE:
  8781.     case TN_DEC_PRE:
  8782.  
  8783.         call->tnFlags |= TNF_CALL_ASGPRE;
  8784.  
  8785.     case TN_INC_POST:
  8786.     case TN_DEC_POST:
  8787.  
  8788.         call->tnFlags |= TNF_CALL_ASGOP;
  8789.         break;
  8790.     }
  8791.  
  8792.     return  call;
  8793. }
  8794.  
  8795. /*****************************************************************************
  8796.  *
  8797.  *  Compute the cost of converting the expression 'srcExpr' to the type given
  8798.  *  by 'dstType'. If this cost is lower than lowCost, return the new lowest
  8799.  *  cost and update *bestCn1 (or *bestCnv2 if the cost is the same).
  8800.  */
  8801.  
  8802. unsigned            compiler::cmpMeasureConv(Tree       srcExpr,
  8803.                                              TypDef     dstType,
  8804.                                              unsigned   lowCost,
  8805.                                              SymDef     convSym,
  8806.                                              SymDef   * bestCnv1,
  8807.                                              SymDef   * bestCnv2)
  8808. {
  8809.     int             cnvCost1;
  8810.     int             cnvCost2;
  8811.     unsigned        cnvCost;
  8812.  
  8813.     ArgDef          argList;
  8814.  
  8815. #ifdef  SHOW_OVRS_OF_CONVS
  8816.     printf("Source typ: %s\n", cmpGlobalST->stTypeName(srcExpr->tnType, NULL, NULL, NULL, false));
  8817. #endif
  8818.  
  8819.     do
  8820.     {
  8821.         assert(convSym->sdType->tdTypeKind == TYP_FNC);
  8822.  
  8823.         /* Get hold of the conversion's source and target type */
  8824.  
  8825.         argList = convSym->sdType->tdFnc.tdfArgs.adArgs;
  8826.  
  8827.         /* There should be exactly one parameter */
  8828.  
  8829.         assert(argList && argList->adNext == NULL);
  8830.  
  8831. #ifdef  SHOW_OVRS_OF_CONVS
  8832.         printf("\nConsider '%s':\n", cmpGlobalST->stTypeName(convSym->sdType, convSym, NULL, NULL, false));
  8833. //      printf("    Formal: %s\n", cmpGlobalST->stTypeName(argList->adType, NULL, NULL, NULL, false));
  8834. #endif
  8835.  
  8836.         /* Compute the cost of converting to the argument type */
  8837.  
  8838.         cnvCost1 = cmpConversionCost(srcExpr, argList->adType, true);
  8839.         if  (cnvCost1 < 0)
  8840.             goto NEXT;
  8841.  
  8842. #ifdef  SHOW_OVRS_OF_CONVS
  8843.         printf("    Cost 1: %d\n", cnvCost1);
  8844. #endif
  8845.  
  8846.         /* Add the cost of converting the return value to the target type */
  8847.  
  8848.         cmpConvOperExpr->tnType = convSym->sdType->tdFnc.tdfRett;
  8849.         cmpConvOperExpr->tnVtyp = cmpConvOperExpr->tnType->tdTypeKindGet();
  8850.  
  8851.         cnvCost2 = cmpConversionCost(cmpConvOperExpr, dstType, true);
  8852.  
  8853. #ifdef  SHOW_OVRS_OF_CONVS
  8854.         printf("    Cost 2: %d\n", cnvCost2);
  8855. #endif
  8856.  
  8857.         if  (cnvCost2 < 0)
  8858.             goto NEXT;
  8859.  
  8860.         /* The total cost is the sum of both costs, see if it's a new low */
  8861.  
  8862.         cnvCost  = cnvCost1 + cnvCost2 + 10;
  8863.  
  8864. //      printf("    Cost = %2u for %s\n", cnvCost, cmpGlobalST->stTypeName(convSym->sdType, convSym, NULL, NULL, true));
  8865.  
  8866.         if  (cnvCost < lowCost)
  8867.         {
  8868.             /* We have a new champion! */
  8869.  
  8870.             *bestCnv1 = convSym;
  8871.             *bestCnv2 = NULL;
  8872.  
  8873.             lowCost = cnvCost;
  8874.             goto NEXT;
  8875.         }
  8876.  
  8877.         /* It could be a draw */
  8878.  
  8879.         if  (lowCost == cnvCost)
  8880.         {
  8881.             assert(*bestCnv1);
  8882.  
  8883.             /* Remember the first two operators at this cost */
  8884.  
  8885.             if  (*bestCnv2 == NULL)
  8886.                  *bestCnv2  = convSym;
  8887.         }
  8888.  
  8889.     NEXT:
  8890.  
  8891.         convSym = convSym->sdFnc.sdfNextOvl;
  8892.     }
  8893.     while (convSym);
  8894.  
  8895. #ifdef  SHOW_OVRS_OF_CONVS
  8896.     if  (*bestCnv1) printf("\nChose '%s'\n", cmpGlobalST->stTypeName((*bestCnv1)->sdType, *bestCnv1, NULL, NULL, false));
  8897. #endif
  8898.  
  8899.     return  lowCost;
  8900. }
  8901.  
  8902. /*****************************************************************************
  8903.  *
  8904.  *  Two expressions - at least one of which is a struct - are being compared,
  8905.  *  see if this is legal. If so, return an expression that will compute the
  8906.  *  result of the comparison, otherwise return NULL.
  8907.  */
  8908.  
  8909. Tree                compiler::cmpCompareValues(Tree expr, Tree op1, Tree op2)
  8910. {
  8911.     Tree            call;
  8912.  
  8913.     TypDef          op1Type = op1->tnType;
  8914.     TypDef          op2Type = op2->tnType;
  8915.  
  8916.     SymDef          op1Conv;
  8917.     SymDef          op2Conv;
  8918.  
  8919.     treeOps         relOper  = expr->tnOperGet();
  8920.  
  8921.     ovlOpFlavors    ovlOper  = cmpGlobalST->stOvlOperIndex(treeOp2token(relOper), 2);
  8922.  
  8923.     bool            equality = (relOper == TN_EQ || relOper == TN_NE);
  8924.  
  8925.     /* Find all the operators that might be used for the comparison */
  8926.  
  8927.     if  (op1Type->tdTypeKind == TYP_CLASS &&
  8928.          op1Type->tdClass.tdcValueType)
  8929.     {
  8930.         SymDef          op1Cls = op1Type->tdClass.tdcSymbol;
  8931.  
  8932.         /* First look for an exact match on C++ style operator */
  8933.  
  8934.         op1Conv = cmpGlobalST->stLookupOper(ovlOper, op1Cls);
  8935.         if  (op1Conv)
  8936.             goto DONE_OP1;
  8937.  
  8938.         /* If we're testing equality, give preference to operator equals */
  8939.  
  8940.         if  (equality)
  8941.         {
  8942.             op1Conv = cmpGlobalST->stLookupOper(OVOP_EQUALS, op1Cls);
  8943.             if  (op1Conv)
  8944.                 goto DONE_OP1;
  8945.         }
  8946.  
  8947.         op1Conv = cmpGlobalST->stLookupOper(OVOP_COMPARE, op1Cls);
  8948.     }
  8949.     else
  8950.         op1Conv = NULL;
  8951.  
  8952. DONE_OP1:
  8953.  
  8954.     if  (op2Type->tdTypeKind == TYP_CLASS &&
  8955.          op2Type->tdClass.tdcValueType    && op1Type != op2Type)
  8956.     {
  8957.         SymDef          op2Cls = op2Type->tdClass.tdcSymbol;
  8958.  
  8959.         /* First look for an exact match on C++ style operator */
  8960.  
  8961.         op2Conv = cmpGlobalST->stLookupOper(ovlOper, op2Cls);
  8962.         if  (op2Conv)
  8963.             goto DONE_OP1;
  8964.  
  8965.         /* If we're testing equality, give preference to operator equals */
  8966.  
  8967.         if  (equality)
  8968.         {
  8969.             op2Conv = cmpGlobalST->stLookupOper(OVOP_EQUALS, op2Cls);
  8970.             if  (op2Conv)
  8971.                 goto DONE_OP2;
  8972.         }
  8973.  
  8974.         op2Conv = cmpGlobalST->stLookupOper(OVOP_COMPARE, op2Cls);
  8975.     }
  8976.     else
  8977.         op2Conv = NULL;
  8978.  
  8979. DONE_OP2:
  8980.  
  8981. #if     0
  8982. #ifdef  DEBUG
  8983.  
  8984.     if  (!strcmp(cmpCurFncSym->sdSpelling(), "<put method name here"))
  8985.     {
  8986.         printf("\nCheck user-defined comparison operator:\n");
  8987.  
  8988.         printf("   Op1 type = '%s'\n", cmpGlobalST->stTypeName(op1->tnType, NULL, NULL, NULL, false));
  8989.         printf("   Op2 type = '%s'\n", cmpGlobalST->stTypeName(op2->tnType, NULL, NULL, NULL, false));
  8990.  
  8991.         printf("\n");
  8992.  
  8993.         if  (op1Conv)
  8994.         {
  8995.             SymDef          sym;
  8996.             printf("op1Conv:\n");
  8997.             for (sym = op1Conv; sym; sym = sym->sdFnc.sdfNextOvl)
  8998.                 printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  8999.             printf("\n");
  9000.         }
  9001.  
  9002.         if  (op2Conv)
  9003.         {
  9004.             SymDef          sym;
  9005.             printf("op2Conv:\n");
  9006.             for (sym = op2Conv; sym; sym = sym->sdFnc.sdfNextOvl)
  9007.                 printf("    %s\n", cmpGlobalST->stTypeName(sym->sdType, sym, NULL, NULL, true));
  9008.             printf("\n");
  9009.         }
  9010.     }
  9011.  
  9012. #endif
  9013. #endif
  9014.  
  9015.     /* See if we can pick an operator to call */
  9016.  
  9017.     cmpCompOperCall->tnOper = TN_LIST;
  9018.  
  9019.     if  (op1Conv)
  9020.     {
  9021.         if  (op2Conv)
  9022.         {
  9023.             cmpCompOperFunc->tnOp.tnOp1 = cmpCompOperFnc1;
  9024.             cmpCompOperFunc->tnOp.tnOp2 = cmpCompOperFnc2;
  9025.  
  9026.             cmpCompOperCall->tnOp.tnOp1 = cmpCompOperFunc;
  9027.         }
  9028.         else
  9029.             cmpCompOperCall->tnOp.tnOp1 = cmpCompOperFnc1;
  9030.     }
  9031.     else
  9032.     {
  9033.         if  (op2Conv == NULL)
  9034.             return  NULL;
  9035.  
  9036.         cmpCompOperCall->tnOp.tnOp1 = cmpCompOperFnc2;
  9037.     }
  9038.  
  9039.     /* Fill in the node to hold the arguments and conversion operator(s) */
  9040.  
  9041.     cmpCompOperArg1->tnOp.tnOp1         = op1;
  9042.     cmpCompOperArg1->tnOp.tnOp2         = cmpCompOperArg2;  // CONSIDER: do only once
  9043.     cmpCompOperArg2->tnOp.tnOp1         = op2;
  9044.     cmpCompOperArg2->tnOp.tnOp2         = NULL;             // CONSIDER: do only once
  9045.  
  9046.     cmpCompOperFnc1->tnFncSym.tnFncSym  = op1Conv;
  9047.     cmpCompOperFnc1->tnFncSym.tnFncArgs = cmpCompOperArg1;
  9048.     cmpCompOperFnc1->tnFncSym.tnFncObj  = NULL;
  9049.     cmpCompOperFnc1->tnFncSym.tnFncScp  = NULL;
  9050.  
  9051.     cmpCompOperFnc2->tnFncSym.tnFncSym  = op2Conv;
  9052.     cmpCompOperFnc2->tnFncSym.tnFncArgs = cmpCompOperArg1;
  9053.     cmpCompOperFnc2->tnFncSym.tnFncObj  = NULL;
  9054.     cmpCompOperFnc2->tnFncSym.tnFncScp  = NULL;
  9055.  
  9056.     cmpCompOperCall->tnOp.tnOp2         = cmpCompOperArg1;  // CONSIDER: do only once
  9057.  
  9058.     call = cmpCheckFuncCall(cmpCompOperCall);
  9059.  
  9060.     if  (call && call->tnOper != TN_ERROR)
  9061.     {
  9062.         SymDef          fncSym;
  9063.  
  9064.         Tree            arg1;
  9065.         Tree            arg2;
  9066.  
  9067.         /* Success - get hold of the chosen operator method */
  9068.  
  9069.         assert(call->tnOper == TN_FNC_SYM);
  9070.         fncSym = call->tnFncSym.tnFncSym;
  9071.         assert(fncSym->sdSymKind == SYM_FNC);
  9072.         assert(fncSym->sdFnc.sdfOper == OVOP_EQUALS  ||
  9073.                fncSym->sdFnc.sdfOper == OVOP_COMPARE ||
  9074.                fncSym->sdFnc.sdfOper == ovlOper);
  9075.  
  9076.         /* Create a bona fide function call tree */
  9077.  
  9078.         arg1 = cmpCreateExprNode(NULL, TN_LIST   , cmpTypeVoid, cmpCompOperArg2->tnOp.tnOp1, NULL);
  9079.         arg2 = cmpCreateExprNode(NULL, TN_LIST   , cmpTypeVoid, cmpCompOperArg1->tnOp.tnOp1, arg1);
  9080.         call = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpDirectType(fncSym->sdType->tdFnc.tdfRett));
  9081.         call->tnFncSym.tnFncSym  = fncSym;
  9082.         call->tnFncSym.tnFncArgs = arg2;
  9083.         call->tnFncSym.tnFncObj  = NULL;
  9084.         call->tnFncSym.tnFncScp  = NULL;
  9085.  
  9086.         /* Did we end up using operator equals or compare ? */
  9087.  
  9088.         if  (fncSym->sdFnc.sdfOper == OVOP_EQUALS)
  9089.         {
  9090.             assert(call->tnVtyp == TYP_BOOL);
  9091.  
  9092.             /* Compute the result */
  9093.  
  9094.             return  cmpCreateExprNode(NULL,
  9095.                                       (expr->tnOper == TN_EQ) ? TN_NE : TN_EQ,
  9096.                                       cmpTypeBool,
  9097.                                       call,
  9098.                                       cmpCreateIconNode(NULL, 0, TYP_BOOL));
  9099.         }
  9100.  
  9101.         if  (fncSym->sdFnc.sdfOper == ovlOper)
  9102.         {
  9103.             return  cmpBooleanize(call, true);
  9104.         }
  9105.         else
  9106.         {
  9107.             assert(fncSym->sdFnc.sdfOper == OVOP_COMPARE);
  9108.  
  9109.             assert(call->tnVtyp == TYP_BOOL ||
  9110.                    call->tnVtyp == TYP_INT);
  9111.         }
  9112.  
  9113.         call = cmpCreateExprNode(NULL,
  9114.                                  relOper,
  9115.                                  cmpTypeBool,
  9116.                                  call,
  9117.                                  cmpCreateIconNode(NULL, 0, TYP_INT));
  9118.     }
  9119.  
  9120.     return  call;
  9121. }
  9122.  
  9123. /*****************************************************************************
  9124.  *
  9125.  *  Return an expression that will yield the typeinfo instance for the given
  9126.  *  type:
  9127.  *
  9128.  *          System.Type::GetTypeFromHandle(tokenof(type))
  9129.  */
  9130.  
  9131. Tree                compiler::cmpTypeIDinst(TypDef type)
  9132. {
  9133.     Tree            expr;
  9134.     Tree            func;
  9135.  
  9136.     assert(type && type->tdIsManaged);
  9137.  
  9138.     /* Call "GetTypeFromHandle" passing it a token for the type */
  9139.  
  9140.     expr = cmpParser->parseCreateOperNode(TN_NOP  , NULL, NULL);
  9141.     expr->tnType = cmpDirectType(type);
  9142.     expr->tnVtyp = expr->tnType->tdTypeKindGet();
  9143.  
  9144.     expr = cmpParser->parseCreateOperNode(TN_TOKEN, expr, NULL);
  9145.     expr = cmpParser->parseCreateOperNode(TN_LIST , expr, NULL);
  9146.     func = cmpParser->parseCreateUSymNode(cmpFNsymGetTPHget());
  9147.     expr = cmpParser->parseCreateOperNode(TN_CALL , func, expr);
  9148.  
  9149.     /* Bind the expression and return it */
  9150.  
  9151.     return  cmpBindExpr(expr);
  9152. }
  9153.  
  9154. /*****************************************************************************
  9155.  *
  9156.  *  Given a property accessor method, find the corresponding property field
  9157.  *  and set *isSetPtr to true if the accessor is a "setter". Returns NULL if
  9158.  *  the property field can't be found.
  9159.  */
  9160.  
  9161. SymDef              compiler::cmpFindPropertyDM(SymDef accSym, bool *isSetPtr)
  9162. {
  9163.     const   char *  fnam;
  9164.     SymDef          sym;
  9165.  
  9166.     assert(accSym);
  9167.     assert(accSym->sdSymKind == SYM_FNC);
  9168.     assert(accSym->sdFnc.sdfProperty);
  9169.  
  9170.     // The following is a pretty awful hack, you know ...
  9171.  
  9172.     fnam = accSym->sdSpelling();
  9173.  
  9174.     if      (!memcmp(fnam, "get_", 4))
  9175.     {
  9176.         *isSetPtr = false;
  9177.     }
  9178.     else if (!memcmp(fnam, "set_", 4))
  9179.     {
  9180.         *isSetPtr = true;
  9181.     }
  9182.     else
  9183.         return  NULL;
  9184.  
  9185.     sym = cmpGlobalST->stLookupClsSym(cmpGlobalHT->hashString(fnam+4), accSym->sdParent);
  9186.  
  9187.     while (sym)
  9188.     {
  9189.         if  (sym->sdProp.sdpGetMeth == accSym)
  9190.         {
  9191.             assert(*isSetPtr == false);
  9192.             return  sym;
  9193.         }
  9194.  
  9195.         if  (sym->sdProp.sdpSetMeth == accSym)
  9196.         {
  9197.             assert(*isSetPtr ==  true);
  9198.             return  sym;
  9199.         }
  9200.  
  9201.         sym = sym->sdProp.sdpNextOvl;
  9202.     }
  9203.  
  9204.     return  NULL;
  9205. }
  9206.  
  9207. /*****************************************************************************
  9208.  *
  9209.  *  Given a non-empty function argument list, append the given argument(s) to
  9210.  *  the end of the list.
  9211.  */
  9212.  
  9213. Tree                compiler::cmpAppend2argList(Tree args, Tree addx)
  9214. {
  9215.     Tree            temp;
  9216.  
  9217.     assert(args && args->tnOper == TN_LIST);
  9218.     assert(addx);
  9219.  
  9220.     /* Some callers don't wrap a single argument value, we do it for them */
  9221.  
  9222.     if  (addx->tnOper != TN_LIST)
  9223.         addx = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, addx, NULL);
  9224.  
  9225.     /* Find the end of the argument list and attach the new addition */
  9226.  
  9227.     for (temp = args; temp->tnOp.tnOp2; temp = temp->tnOp.tnOp2)
  9228.     {
  9229.         assert(temp && temp->tnOper == TN_LIST);
  9230.     }
  9231.  
  9232.     temp->tnOp.tnOp2 = addx;
  9233.  
  9234.     return  args;
  9235. }
  9236.  
  9237. /*****************************************************************************
  9238.  *
  9239.  *  Bind a property reference. If 'args' is non-NULL, this is an indexed
  9240.  *  property reference. If 'asgx' is non-NULL, the property is a target
  9241.  *  of an assignment.
  9242.  */
  9243.  
  9244. Tree                compiler::cmpBindProperty(Tree      expr,
  9245.                                               Tree      args,
  9246.                                               Tree      asgx)
  9247. {
  9248.     Tree            call;
  9249.  
  9250.     bool            found;
  9251.     SymDef          propSym;
  9252.     SymDef          funcSym;
  9253.     TypDef          propType;
  9254.  
  9255.     assert(expr->tnOper == TN_PROPERTY);
  9256.     propSym = expr->tnVarSym.tnVarSym;
  9257.     assert(propSym->sdSymKind == SYM_PROP);
  9258.  
  9259.     /* If have an assignment, wrap its RHS as an argument node */
  9260.  
  9261.     if  (asgx)
  9262.     {
  9263.         assert(asgx->tnOper != TN_LIST);
  9264.  
  9265.         asgx = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, asgx, NULL);
  9266.     }
  9267.  
  9268.     /* Is this a call or a "simple" reference? */
  9269.  
  9270.     if  (args)
  9271.     {
  9272.         if  (args->tnOper != TN_LIST)
  9273.             args = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, args, NULL);
  9274.  
  9275.         if  (asgx)
  9276.         {
  9277.             /* Append the RHS of the assignment to the argument list */
  9278.  
  9279.             args = cmpAppend2argList(args, asgx);
  9280.         }
  9281.     }
  9282.     else
  9283.     {
  9284.         args = asgx;
  9285.     }
  9286.  
  9287.     /* Find the appropriate method */
  9288.  
  9289.     found   = false;
  9290.     funcSym = cmpFindPropertyFN(propSym->sdParent, propSym->sdName, args, !asgx, &found);
  9291.  
  9292.     if  (!funcSym)
  9293.     {
  9294.         Ident           propName = asgx ? cmpIdentSet : cmpIdentGet;
  9295.  
  9296.         if  (found)
  9297.         {
  9298.             cmpError(ERRnoPropOvl, propSym->sdParent->sdName, propName, propSym->sdName);
  9299.         }
  9300.         else
  9301.         {
  9302.             cmpError(ERRnoPropSym, propSym->sdParent->sdName, propName, propSym->sdName);
  9303.         }
  9304.  
  9305.         return cmpCreateErrNode();
  9306.     }
  9307.  
  9308.     // UNDONE: Need to check whether the property is static, etc!
  9309.  
  9310.     /* Figure out the resulting type */
  9311.  
  9312.     propType = propSym->sdType;
  9313.     if  (propType->tdTypeKind == TYP_FNC)
  9314.         propType = propType->tdFnc.tdfRett;
  9315.  
  9316.     /* Create a call to the appropriate property accessor */
  9317.  
  9318.     call = cmpCreateExprNode(NULL, TN_FNC_SYM, propType);
  9319.     call->tnFncSym.tnFncSym  = funcSym;
  9320.     call->tnFncSym.tnFncArgs = args;
  9321.     call->tnFncSym.tnFncObj  = expr->tnVarSym.tnVarObj;
  9322.     call->tnFncSym.tnFncScp  = NULL;
  9323.  
  9324.     call = cmpCheckFuncCall(call);
  9325.  
  9326.     /* Is the call supposed to be non-virtual? */
  9327.  
  9328.     if  (expr->tnVarSym.tnVarObj &&
  9329.          expr->tnVarSym.tnVarObj->tnOper == TN_LCL_SYM)
  9330.     {
  9331.         if  (expr->tnVarSym.tnVarObj->tnFlags & TNF_LCL_BASE)
  9332.             call->tnFlags |= TNF_CALL_NVIRT;
  9333.     }
  9334.  
  9335.     return  call;
  9336. }
  9337.  
  9338. /*****************************************************************************
  9339.  *
  9340.  *  Bind a use of the "va_start" or "va_arg" intrinsic.
  9341.  */
  9342.  
  9343. Tree                compiler::cmpBindVarArgUse(Tree call)
  9344. {
  9345.     SymDef          fsym;
  9346.  
  9347.     Tree            arg1;
  9348.     Tree            arg2;
  9349.  
  9350.     SymDef          meth;
  9351.  
  9352.     Tree            expr;
  9353.  
  9354.     assert(call->tnOper == TN_FNC_SYM);
  9355.     fsym = call->tnFncSym.tnFncSym;
  9356.  
  9357.     /* Is this "va_start" ? */
  9358.  
  9359.     if  (fsym == cmpFNsymVAbeg)
  9360.     {
  9361.         /* Make sure we are within a varargs function */
  9362.  
  9363.         if  (!cmpCurFncSym || !cmpCurFncSym->sdType->tdFnc.tdfArgs.adVarArgs)
  9364.         {
  9365.             cmpError(ERRbadVarArg);
  9366.             return cmpCreateErrNode();
  9367.         }
  9368.     }
  9369.     else
  9370.     {
  9371.         assert(fsym == cmpFNsymVAget);
  9372.     }
  9373.  
  9374.     /* There must be two arguments */
  9375.  
  9376.     arg1 = call->tnFncSym.tnFncArgs;
  9377.  
  9378.     if  (!arg1 || !arg1->tnOp.tnOp2)
  9379.     {
  9380.         cmpError(ERRmisgArg, fsym);
  9381.         return cmpCreateErrNode();
  9382.     }
  9383.  
  9384.     assert(arg1->tnOper == TN_LIST);
  9385.     arg2 = arg1->tnOp.tnOp2;
  9386.     assert(arg2->tnOper == TN_LIST);
  9387.  
  9388.     if  (arg2->tnOp.tnOp2)
  9389.     {
  9390.         cmpError(ERRmanyArg, fsym);
  9391.         return cmpCreateErrNode();
  9392.     }
  9393.  
  9394.     arg1 = arg1->tnOp.tnOp1;
  9395.     arg2 = arg2->tnOp.tnOp1;
  9396.  
  9397.     /* The first argument must be a local of type 'ArgIterator' */
  9398.  
  9399.     cmpFindArgIterType();
  9400.  
  9401.     if  ((arg1->tnOper != TN_LCL_SYM   ) ||
  9402.          (arg1->tnFlags & TNF_BEEN_CAST) || !symTab::stMatchTypes(arg1->tnType,
  9403.                                                                   cmpClassArgIter->sdType))
  9404.     {
  9405.         cmpError(ERRnotArgIter);
  9406.         return cmpCreateErrNode();
  9407.     }
  9408.  
  9409.     /* Is this va_start or va_arg ? */
  9410.  
  9411.     if  (fsym == cmpFNsymVAbeg)
  9412.     {
  9413.         /* The second argument must be the function's last argument */
  9414.  
  9415.         if  ((arg2->tnOper != TN_LCL_SYM   ) ||
  9416.              (arg2->tnFlags & TNF_BEEN_CAST) ||
  9417.              !arg2->tnLclSym.tnLclSym->sdVar.sdvArgument)
  9418.         {
  9419.             cmpError(ERRnotLastArg);
  9420.             return cmpCreateErrNode();
  9421.         }
  9422.  
  9423.         /* Find the proper ArgIterator constructor */
  9424.  
  9425.         meth = cmpCtorArgIter;
  9426.         if  (!meth)
  9427.         {
  9428.             SymDef          rtah;
  9429.             ArgDscRec       args;
  9430.             TypDef          type;
  9431.  
  9432.             /* Find the "RuntimeArgumentHandle" type */
  9433.  
  9434.             rtah = cmpGlobalST->stLookupNspSym(cmpGlobalHT->hashString("RuntimeArgumentHandle"),
  9435.                                                NS_NORM,
  9436.                                                cmpNmSpcSystem);
  9437.  
  9438.             if  (!rtah || rtah->sdSymKind         != SYM_CLASS
  9439.                        || rtah->sdClass.sdcFlavor != STF_STRUCT)
  9440.             {
  9441.                 cmpGenFatal(ERRbltinTp, "System::RuntimeArgumentHandle");
  9442.             }
  9443.  
  9444.             /* Create the appropriate argument list */
  9445.  
  9446.             cmpParser->parseArgListNew(args,
  9447.                                        2,
  9448.                                        false, rtah->sdType,
  9449.                                               cmpGlobalST->stNewRefType(TYP_PTR, cmpTypeInt),
  9450.                                               NULL);
  9451.  
  9452.             /* Create the type and look for a matching constructor */
  9453.  
  9454.             type = cmpGlobalST->stNewFncType(args, cmpTypeVoid);
  9455.             meth = cmpGlobalST->stLookupOper(OVOP_CTOR_INST, cmpClassArgIter); assert(meth);
  9456.             meth = cmpCurST->stFindOvlFnc(meth, type); assert(meth);
  9457.  
  9458.             /* Remember the constructor for next time */
  9459.  
  9460.             cmpCtorArgIter = meth;
  9461.         }
  9462.  
  9463.         /* Wrap the call in a "va_start" node */
  9464.  
  9465.         expr = cmpCreateExprNode(NULL, TN_VARARG_BEG, cmpTypeVoid);
  9466.  
  9467.         /* This thing doesn't return any value */
  9468.  
  9469.         expr->tnVtyp = TYP_VOID;
  9470.         expr->tnType = cmpTypeVoid;
  9471.     }
  9472.     else
  9473.     {
  9474.         TypDef          type;
  9475.  
  9476.         /* The second argument must be a type */
  9477.  
  9478.         if  (arg2->tnOper != TN_TYPE)
  9479.             return cmpCreateErrNode(ERRbadVAarg);
  9480.  
  9481.         /* Make sure the type is acceptable */
  9482.  
  9483.         type = arg2->tnType;
  9484.  
  9485.         switch (type->tdTypeKind)
  9486.         {
  9487.         case TYP_ARRAY:
  9488.             UNIMPL("need to decay array to pointer, right?");
  9489.  
  9490.         case TYP_VOID:
  9491.             cmpError(ERRbadVAtype, type);
  9492.             return cmpCreateErrNode();
  9493.         }
  9494.  
  9495.         /* Wrap the call in a "va_arg" node */
  9496.  
  9497.         expr = cmpCreateExprNode(NULL, TN_VARARG_GET, type);
  9498.  
  9499.         /* Find the 'GetNextArg' method */
  9500.  
  9501.         meth = cmpGetNextArgFN;
  9502.         if  (!meth)
  9503.         {
  9504.             ArgDscRec       args;
  9505.             TypDef          type;
  9506.  
  9507.             /* Create the method type and look for a matching method */
  9508.  
  9509. #if MGDDATA
  9510.             args = new ArgDscRec;
  9511. #else
  9512.             memset(&args, 0, sizeof(args));
  9513. #endif
  9514.  
  9515.             type = cmpGlobalST->stNewFncType(args, cmpGlobalST->stIntrinsicType(TYP_REFANY));
  9516.  
  9517.             meth = cmpGlobalST->stLookupClsSym(cmpIdentGetNArg, cmpClassArgIter); assert(meth);
  9518.             meth = cmpCurST->stFindOvlFnc(meth, type); assert(meth);
  9519.  
  9520.             /* Remember the method for next time */
  9521.  
  9522.             cmpGetNextArgFN = meth;
  9523.         }
  9524.     }
  9525.  
  9526.     /* Replace the original function with the constructor/nextarg method */
  9527.  
  9528.     call->tnFncSym.tnFncSym  = meth;
  9529.     call->tnFncSym.tnFncArgs = NULL;
  9530.  
  9531.     /* The call doesn't need to be virtual */
  9532.  
  9533.     call->tnFlags           |= TNF_CALL_NVIRT;
  9534.  
  9535.     /* Stash the method and the two arguments under the vararg node */
  9536.  
  9537.     expr->tnOp.tnOp1 = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, arg1,
  9538.                                                                      arg2);
  9539.     expr->tnOp.tnOp2 = call;
  9540.  
  9541.     return  expr;
  9542. }
  9543.  
  9544. /*****************************************************************************/
  9545. /*****************************************************************************/
  9546.