Rune - refactor resolve-time constant evaluation
[rune.git] / librune / resolve.c
1 /*
2  * RESOLVE.C    - Resolve parser tree
3  *
4  * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved.  See the  
5  *    COPYRIGHT file at the base of the distribution.
6  *
7  * This module is responsible for resolving unresolved types and
8  * classes, generating offsets for DeclBlock's and declarations, and
9  * resolving type-rules for expressions in the expression tree.
10  *
11  * We can reach the entire tree by resolving the top-level import
12  * statement's DeclBlock.
13  */
14
15 #include "defs.h"
16 #include <dlfcn.h>
17
18 static void ResolveClasses(Stmt *st, int flags);
19 static void ResolveAlignment(Stmt *st, int flags);
20 static void ResolveStorage(Stmt *st, int flags);
21 static void errorDottedId(string_t *ary, const char *ctl, ...);
22
23 static void resolveStmt(SemGroup *isg, Stmt *st, int flags);
24 static Type *resolveReturnType(SemGroup *sg, int flags);
25 static Type *resolveArgsType(SemGroup *sg, int flags);
26 static void resolveDecl(Declaration *d, int flags);
27 static Exp *resolveExp(SemGroup *isg, SemGroup *sg,
28                         Exp *exp, Type *itype, int flags);
29 static Exp *resolveConstExp(SemGroup *isg, SemGroup *sg, Exp *exp, int flags);
30 static Exp *resolveConstExpBool(SemGroup *isg, SemGroup *sg, Exp *exp, int flags, RunTmpStor *ts);
31 static int64_t resolveGetConstExpInt64(Exp *exp);
32 static float128_t resolveGetConstExpFloat128(Exp *exp);
33 static Exp *resolveCompoundExp(SemGroup *isg, SemGroup *sg,
34                         Exp *exp, Type *itype, int flags);
35 static Exp *resolveExpCast(SemGroup *isg, SemGroup *sg,
36                         Exp *exp, Type *ltype, int flags);
37 static Exp *resolveExpOper(SemGroup *isg, SemGroup *sg,
38                         Exp *exp, Type *itype, int flags);
39 static int resolveSemGroup1(SemGroup *sg, int flags);
40 static int resolveSemGroup2(SemGroup *sg, int flags);
41 static void resolveSemGroup3(SemGroup *sg, int flags);
42 static Type *resolveSuperClass(Type *super);
43
44 static void resolveStorageDeclExpAlign(Declaration *d, runesize_t *expalignp,
45                         int flags);
46 static void resolveStorageExpAlign(Exp *exp, runesize_t *expalignp,
47                         int flags);
48 static void resolveStorageTypeExpAlign(Type *type, runesize_t *expalignp,
49                         int flags);
50 static void resolveStorageSemGroupAlign(SemGroup *sg, int flags);
51
52 static void resolveStorageDeclExp(Declaration *d,
53                         runesize_t *offset, runesize_t *goffset);
54 static runesize_t resolveStorageExpOnly(Exp *exp, runesize_t *offset);
55 static void resolveStorageExpSub(Exp *exp, runesize_t *offset);
56 static void resolveStorageExp(Exp *exp, runesize_t *offset);
57
58 static Declaration *findOper(Type *btype, string_t id,
59                         Type *ltype, Type *rtype, int flags);
60 static Declaration *findExpOper(Exp *exp, int flags);
61 static Declaration *findCast(Type *btype, Type *ltype, Type *rtype, int flags);
62 static void loadExpCopy(Exp *copy, Exp *exp);
63 static void saveExpCopy(Exp *copy, Exp *exp);
64 static Exp *dupExpCopy(Exp *copy, Exp *exp);
65 static void resolveStorageType(Type *type, runesize_t *offset, int isglob);
66 static void resolveStorageSemGroup(SemGroup *sg,
67                         runesize_t noffset, runesize_t ngoffset);
68 static int methodProcThisIsPointer(Type *type);
69
70 static SemGroup *resolvePushSGDepend(SemGroup *sg);
71 static void resolvePopSGDepend(SemGroup *last);
72
73 #define exLhs           copy.ex_Lhs
74 #define exRhs           copy.ex_Rhs
75 #define exFlags         copy.ex_Flags
76 #define exType          copy.ex_Type
77 #define exToken         copy.ex_Token
78 #define exDecl          copy.ex_Decl
79 #define exVisibility    copy.ex_Visibility
80 #define exId            copy.ex_Id
81 #define exArgId         copy.ex_ArgId
82
83 #define ADD_LVALUE(type)                \
84                 resolveType(AddTypeQual((type), SF_LVALUE), NULL, flags)
85 #define DEL_LVALUE(type)                \
86                 resolveType(DelTypeQual((type), SF_LVALUE), NULL, flags)
87 #define RESOLVETYPE(type)               \
88                 resolveType((type), NULL, flags)
89 #define RESOLVETYPEADJ(type, adjtype)   \
90                 resolveType((type), adjtype, flags)
91
92 #define RESOLVE_AUTOCAST        0x0001  /* autocast to expected type */
93 #define RESOLVE_CONSTEXP        0x0002  /* resolve for const interpretation */
94
95 void
96 ResolveProject(Parse *p, Stmt *st)
97 {
98         int i;
99
100         dassert_stmt(st, st->st_Op == ST_Import);
101
102         /*
103          * General project
104          */
105         ResolveClasses(st, 0);
106         resolveStmt(st->st_MyGroup, st, 0);
107         ResolveAlignment(st, 0);
108         ResolveStorage(st, 0);
109
110         /*
111          * Interpreter or Generator may reference our global internal types
112          * directly, so make sure they are all resolved.
113          */
114         for (i = 0; BaseTypeAry[i]; ++i)
115                 resolveType(BaseTypeAry[i], NULL, 0);
116
117         /*
118          * Resolve all types registered by DLLs
119          */
120         {
121                 TypeRegNode *tr;
122
123                 RUNE_FOREACH(tr, &TypeRegList, tr_Node)
124                         resolveType(tr->tr_Type, NULL, 0);
125         }
126
127
128         p->p_Format = PFMT_RESOLVED;
129
130         CollapseProject(st);
131 }
132
133 /*
134  * ResolveClasses() -   Resolve superclasses and do class merge 
135  *
136  *      This code implements the most complex feature of the language:
137  *      subclassing and refinement.  
138  *
139  *      The hardest thing we have to do is 'dup' declarations and code in
140  *      order to implement subclassing and refinement.  For example, a
141  *      procedure defined in Integer must be dup'd for each subclass of
142  *      Integer.  We have to do this because storage requirements will
143  *      change due to both subclassing and refinement.  Even auto variables
144  *      may wind up with different types between superclass and subclass.
145  *
146  *      We must scan ST_Import and ST_Class statements.
147  */
148 static void
149 ResolveClasses(Stmt *st, int flags)
150 {
151         SemGroup *sg = st->st_MyGroup;
152
153         /*
154          * Resolver interlock.  Assert that we aren't looping.  A loop can
155          * occur if class A embeds class B and class B embeds class A
156          * (verses a pointer to A).
157          */
158         dassert_stmt(st, (st->st_Flags & STF_RESOLVING) == 0);
159         if (st->st_Flags & STF_RESOLVED)
160                 return;
161         st->st_Flags |= STF_RESOLVING;
162
163         /*
164          * If this is a subclass, integrate the superclass into it
165          */
166         if (st->st_Op == ST_Class && st->st_ClassStmt.es_Super) {
167                 Type *super = st->st_ClassStmt.es_Super;
168                 Stmt *sst;
169                 Declaration *d;
170                 Declaration *rd;
171                 SemGroup *tsg;
172
173                 /*
174                  * Locate the superclass.  'super' does not appear in any
175                  * other list.. this is a unique Type structure.
176                  */
177                 dassert_stmt(st, super->ty_Op == TY_UNRESOLVED);
178                 do {
179                         super = resolveSuperClass(super);
180                         if (super == NULL) {
181                                 fprintf(stderr,
182                                         "Unable to resolve superclass of %s\n",
183                                         st->st_ClassStmt.es_Decl->d_Id);
184                                 dassert_stmt(st, 0);
185                         }
186                 } while (super->ty_Op == TY_UNRESOLVED);
187
188                 dassert_stmt(st, super->ty_Op == TY_CLASS);
189
190                 /*
191                  * Cleanup (XXX free qualified segments??)
192                  */
193                 st->st_ClassStmt.es_Super = super;
194                 st->st_ClassStmt.es_Decl->d_ClassDecl.ed_Super = super;
195
196                 /*
197                  * Inherit internal unsigned integer and floating point flags
198                  * and a few others.
199                  */
200                 sg->sg_Flags |= super->ty_ClassType.et_SemGroup->sg_Flags &
201                                 (SGF_ISINTEGER | SGF_ISUNSIGNED |
202                                  SGF_ISFLOATING | SGF_ISBOOL |
203                                  SGF_HASASS | SGF_GHASASS |
204                                  SGF_HASLVPTR | SGF_GHASLVPTR);
205
206                 /*
207                  * Locate the class statement associated with the superclass
208                  * and resolve it.
209                  */
210                 sst = super->ty_ClassType.et_SemGroup->sg_Stmt;
211                 dassert_stmt(st, sst != NULL);
212                 dassert_stmt(st, sst->st_Op == ST_Class);
213
214                 ResolveClasses(sst, flags);
215
216                 /*
217                  * Assign the sg_Level for the subclass.  This is used
218                  * for semantic searches when a subclass is passed to a
219                  * procedure expecting the superclass.
220                  */
221                 sg->sg_Level = sst->st_MyGroup->sg_Level + 1;
222
223                 /*
224                  * First move all the declarations from sg to tsg so we
225                  * can merge the superclass properly (keep all the d_Index's
226                  * correct).  Note that tsg is not 100% integrated so we can
227                  * only use it for search purposes.  We absolutely CANNOT
228                  * DupDeclaration() into tsg!
229                  */
230                 tsg = AllocSemGroup(SG_CLASS, sg->sg_Parse, NULL, sg->sg_Stmt);
231                 while ((d = RUNE_FIRST(&sg->sg_DeclList)) != NULL) {
232                         RenameDecl(d, tsg);
233                 }
234                 sg->sg_DeclCount = 0;   /* reset */
235
236                 /*
237                  * Merge the superclass into this class, in sequence.
238                  * Iterate through declarations in the superclass and pull
239                  * them into the subclass.  Figure out compatibility between
240                  * super and subclasses.
241                  */
242                 RUNE_FOREACH(d, &sst->st_MyGroup->sg_DeclList, d_Node) {
243                         Declaration *nd;
244                         int eno = 0;
245
246                         dassert(d->d_Level != NULL &&
247                                 d->d_Level->sg_Level < sg->sg_Level);
248
249                         /*
250                          * See if the superclass decl conflicts with a
251                          * subclass decl.  If there is no conflict pull it
252                          * into the subclass and adjust the visibility.
253                          * Note that the superclass may have duplicate ids,
254                          * but they will be at different levels if so.
255                          *
256                          * The super linkage is required when findDecl()
257                          * checks visibility of a declaration hidden relative
258                          * to our subclass, but not necessarily hidden
259                          * relative to the superclass.
260                          *
261                          * XXX overloading
262                          */
263                         rd = FindDeclId(tsg, d->d_Id, &eno);
264                         if (rd == NULL) {
265                                 nd = DupDeclaration(sg, d);
266                                 dassert(d->d_Index == nd->d_Index);
267                                 nd->d_ScopeFlags &= ~SCOPE_ALL_VISIBLE |
268                                                     super->ty_Visibility;
269                                 nd->d_ScopeFlags &= ~SCOPE_REFINE;
270                                 continue;
271                         }
272
273                         /*
274                          * If there is a conflict and we are not refining
275                          * the superclass entity, then pull in the superclass
276                          * entity and make it invisible to sg_Level searches.
277                          * This could bring in multiple levels of the same id.
278                          *
279                          * Note that this may result in multiple ids, but
280                          * they will be at different levels.  In this case
281                          * rd will be at the current level and nd will be
282                          * at some prior level.
283                          *
284                          * Order is important here.
285                          */
286                         if ((rd->d_ScopeFlags & SCOPE_REFINE) == 0) {
287                                 nd = DupDeclaration(sg, d);
288                                 dassert(d->d_Index == nd->d_Index);
289                                 nd->d_ScopeFlags &= ~(SCOPE_ALL_VISIBLE |
290                                                       SCOPE_REFINE);
291 #if 0
292                                 printf(" conflict, not refined, overload\n");
293 #endif
294                                 continue;
295                         }
296
297                         /*
298                          * Ok, we need to refine.  But the superclass may
299                          * contain multiple levels of the same id.  We only
300                          * refine the one that is visible to us.  None of
301                          * these other declarations will be at the same level.
302                          */
303                         if ((d->d_ScopeFlags & SCOPE_ALL_VISIBLE) == 0) {
304                                 nd = DupDeclaration(sg, d);
305                                 dassert(d->d_Index == nd->d_Index);
306                                 nd->d_ScopeFlags &= ~(SCOPE_ALL_VISIBLE |
307                                                       SCOPE_REFINE);
308 #if 0
309                                 printf(" conflict, refined (skip this one)\n");
310 #endif
311                                 continue;
312                         }
313
314                         /*
315                          * Whew!  Finally, we found the superclass decl
316                          * that we wish to refine.  We had better not have
317                          * already refined it or there's something wrong
318                          * with the algorithm.
319                          *
320                          * Since we inherit the superclass method's level
321                          * our method will run in the superclass instead
322                          * of the original, but d_Super still must be set
323                          * for findDecl() to track down visibility relative
324                          * to the superclass methods.
325                          */
326                         RenameDecl(rd, sg);
327                         dassert_decl(rd, rd->d_Super == NULL);
328                         dassert(d->d_Index == rd->d_Index);
329                         rd->d_Level = d->d_Level;
330                         rd->d_Super = d;
331
332                         /*
333                          * This is for the superclass method access special
334                          * case below.
335                          */
336                         if (d->d_Op == DOP_PROC) {
337                                 d->d_Flags |= DF_SUPERCOPY;
338                         }
339                 }
340
341                 /*
342                  * Deal with any remaining elements in tsg.  These are
343                  * 'extensions' to the superclass.  There may also be
344                  * invisible DOP_PROC's to handle the special superclass
345                  * method call case descibed above.
346                  */
347                 while ((rd = RUNE_FIRST(&tsg->sg_DeclList)) != NULL) {
348                         if (rd->d_ScopeFlags & SCOPE_REFINE) {
349                                 if (rd->d_Super == NULL) {
350                                         fprintf(stderr,
351                                                 "Unable to refine %s, it "
352                                                 "does not exist in "
353                                                 "superclass\n",
354                                                 rd->d_Id);
355                                         dassert_decl(rd, 0);
356                                 }
357                         }
358                         RenameDecl(rd, sg);
359                 }
360
361                 FreeSemGroup(tsg);
362
363                 /*
364                  * We have to special case super.method() for a refined method.
365                  * Normally this makes the original method inaccessible (for
366                  * storage), but we want it to work for a procedure so we make
367                  * a copy in tsg.  (we can't dup it directly into sg because it
368                  * will screw up the d_Index).
369                  *
370                  * We must not only clear the scope visibility and the
371                  * temporary refine flag, we also have to clear
372                  * constructor/destructor scope in the copy so only the
373                  * refined constructor/destructor is called, not both the
374                  * refined and the superclass constructor/destructor.
375                  */
376                 RUNE_FOREACH(d, &sst->st_MyGroup->sg_DeclList, d_Node) {
377                         Declaration *nd;
378
379                         if (d->d_Flags & DF_SUPERCOPY) {
380                                 d->d_Flags &= ~DF_SUPERCOPY;
381                                 nd = DupDeclaration(sg, d);
382                                 nd->d_ScopeFlags &= ~(SCOPE_ALL_VISIBLE |
383                                                       SCOPE_REFINE |
384                                                       SCOPE_CONSTRUCTOR |
385                                                       SCOPE_DESTRUCTOR);
386                         }
387                 }
388         } else if (st->st_Op == ST_Class) {
389                 sg->sg_Level = 0;
390         }
391
392         st->st_Flags &= ~STF_RESOLVING;
393         st->st_Flags |= STF_RESOLVED;
394
395         /*
396          * If this is an ST_Import we must recurse through it.  The only
397          * statements under an Import should be Modules.  Well, really just
398          * one module.  And under that module we only care about ST_Import
399          * and ST_Class statements.
400          *
401          * If this is a shared import the statement list will be empty (later
402          * it may be used for import refinement, I dunno).  This is what we
403          * want since we should only resolve a shared import once.
404          */
405         if (st->st_Op == ST_Import) {
406                 Stmt *scan;
407
408                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
409                         Stmt *scan2;
410
411                         dassert_stmt(scan, scan->st_Op == ST_Module);
412                         RUNE_FOREACH(scan2, &scan->st_List, st_Node) {
413                                 if (scan2->st_Op == ST_Import ||
414                                     scan2->st_Op == ST_Class) {
415                                         ResolveClasses(scan2, flags);
416                                 }
417                         }
418                 }
419                 if (st->st_ImportStmt.es_DLL) {
420                         void (*func)(void) = dlsym(st->st_ImportStmt.es_DLL,
421                                                    "resolveClasses");
422                         if (func)
423                                 func();
424                 }
425         }
426 }
427
428 /*
429  * resolveStmt() - Resolve all types, declarations, and semantic refs
430  *
431  *      Resolves all types, declarations, and identifiers.  Additionally
432  *      this function resolves intermediate types for expressions.  Storage
433  *      sizes are resolved but offsets are not assigned to declarations.
434  */
435 void
436 resolveStmt(SemGroup *isg, Stmt *st, int flags)
437 {
438         SemGroup *dep = NULL;
439
440         /*
441          * Process whether we detached as a thread already or not.
442          */
443         if (st->st_Parent)
444                 st->st_Flags |= st->st_Parent->st_Flags & STF_DIDRESULT;
445
446         /*
447          * Deal with unresolved types here
448          */
449         if (st->st_Flags & STF_SEMANTIC) {
450                 SemGroup *sg = st->st_MyGroup;
451                 Type *type;
452
453                 dep = resolvePushSGDepend(sg);
454
455                 RUNE_FOREACH(type, &sg->sg_ClassList, ty_Node) {
456                         if (type->ty_Op == TY_UNRESOLVED) {
457                                 if (resolveSuperClass(type) == NULL) {
458                                         errorDottedId(
459                                                 type->ty_UnresType.et_DottedId,
460                                                 "Unable to resolve class");
461                                         dassert_stmt(st, 0);
462                                 }
463                         }
464                 }
465         }
466
467         /*
468          * Resolve statements.  Don't worry about declarations, those are
469          * handled after this switch.
470          */
471         switch(st->st_Op) {
472         case ST_Import:
473                 /*
474                  * This will just flag the import declaration as resolved
475                  * so the code generator dives it for generation.
476                  */
477                 if (st->st_ImportStmt.es_Decl)
478                         resolveDecl(st->st_ImportStmt.es_Decl, flags);
479                 /* fall through */
480         case ST_Module:
481                 /*
482                  * Recursively resolve contents
483                  */
484                 {
485                         Stmt *scan;
486
487                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
488                                 /*
489                                  * XXX pass isg for import, st_MyGroup for
490                                  * module??
491                                  */
492                                 resolveStmt(st->st_MyGroup, scan, flags);
493                         }
494                         if (st->st_Op == ST_Import &&
495                             st->st_ImportStmt.es_DLL) {
496                                 void (*func)(void) =
497                                         dlsym(st->st_ImportStmt.es_DLL,
498                                               "resolveTypes");
499                                 if (func)
500                                         func();
501                         }
502                 }
503                 break;
504         case ST_Class:
505                 resolveDecl(st->st_ClassStmt.es_Decl, flags);
506                 break;
507         case ST_Typedef:
508                 resolveDecl(st->st_TypedefStmt.es_Decl, flags);
509                 break;
510         case ST_Decl:
511                 /*
512                  * Resolve declarations, skipping any whos context was
513                  * moved to a class (e.g. a declaration at the top level
514                  * of a file like Fd.setfd(...) also exists in the Fd class).
515                  */
516                 {
517                         Declaration *d = st->st_DeclStmt.es_Decl;
518                         int i;
519
520                         for (i = 0; i < st->st_DeclStmt.es_DeclCount; ++i) {
521                                 if (st->st_MyGroup != d->d_MyGroup)
522                                         /*printf("SKIPA %s\n", d->d_Id)*/;
523                                 else
524                                         resolveDecl(d, flags);
525                                 d = RUNE_NEXT(d, d_Node);
526                         }
527                 }
528                 break;
529         case ST_Block:
530                 {
531                         Stmt *scan;
532
533                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
534                                 resolveStmt(isg, scan, flags);
535                         }
536                 }
537                 break;
538         case ST_Nop:
539                 break;
540         case ST_Loop:
541                 if (st->st_LoopStmt.es_Init)
542                         resolveStmt(isg, st->st_LoopStmt.es_Init, flags);
543                 if (st->st_LoopStmt.es_BCond) {
544                         /*
545                          * NOTE: BoolType global implies an rvalue.
546                          */
547                         st->st_LoopStmt.es_BCond =
548                                 resolveExp(isg, st->st_MyGroup,
549                                            st->st_LoopStmt.es_BCond,
550                                            &BoolType, RESOLVE_AUTOCAST);
551                 }
552                 if (st->st_LoopStmt.es_ACond) {
553                         /*
554                          * NOTE: BoolType global implies an rvalue.
555                          */
556                         st->st_LoopStmt.es_ACond =
557                                 resolveExp(isg, st->st_MyGroup,
558                                            st->st_LoopStmt.es_ACond,
559                                            &BoolType, RESOLVE_AUTOCAST);
560                 }
561                 if (st->st_LoopStmt.es_AExp) {
562                         /*
563                          * NOTE: VoidType global implies an rvalue.
564                          */
565                         st->st_LoopStmt.es_AExp =
566                                 resolveExp(isg, st->st_MyGroup,
567                                            st->st_LoopStmt.es_AExp,
568                                            &VoidType, RESOLVE_AUTOCAST);
569                 }
570                 if (st->st_LoopStmt.es_Body) {
571                         resolveStmt(isg, st->st_LoopStmt.es_Body, flags);
572 #if 0
573                         /* remove handled in resolveDecl DOP_PROC */
574                         if ((st->st_LoopStmt.es_Body->st_Flags &
575                              STF_RESOLVED) == 0) {
576                                 ResolveAlignment(st->st_LoopStmt.es_Body,
577                                                  flags);
578                                 ResolveStorage(st->st_LoopStmt.es_Body, flags);
579                         }
580 #endif
581                 }
582                 break;
583         case ST_BreakCont:
584                 break;
585         case ST_Bad:
586                 break;
587         case ST_IfElse:
588                 /*
589                  * NOTE: BoolType global implies an rvalue.
590                  */
591                 st->st_IfStmt.es_Exp = resolveExp(isg, st->st_MyGroup,
592                                                   st->st_IfStmt.es_Exp,
593                                                   &BoolType, RESOLVE_AUTOCAST);
594                 resolveStmt(isg, st->st_IfStmt.es_TrueStmt, flags);
595                 if (st->st_IfStmt.es_FalseStmt)
596                         resolveStmt(isg, st->st_IfStmt.es_FalseStmt, flags);
597                 break;
598         case ST_Return:
599                 /*
600                  * NOTE: lvalue/rvalue depends on return type.
601                  */
602                 st->st_RetStmt.es_ProcRetType =
603                                 resolveReturnType(st->st_MyGroup, flags);
604                 if (st->st_RetStmt.es_Exp) {
605                         if (st->st_Flags & STF_DIDRESULT)
606                                 StmtFatalError(st, TOK_ERR_RESULT_SEQUENCING);
607                         st->st_RetStmt.es_Exp =
608                                 resolveExp(isg, st->st_MyGroup,
609                                            st->st_RetStmt.es_Exp,
610                                            st->st_RetStmt.es_ProcRetType,
611                                            RESOLVE_AUTOCAST);
612                 }
613                 break;
614         case ST_Result:
615                 /*
616                  * NOTE: lvalue/rvalue depends on return type.
617                  */
618                 if (st->st_Flags & STF_DIDRESULT)
619                         StmtFatalError(st, TOK_ERR_RESULT_SEQUENCING);
620                 if ((st->st_Parent->st_Flags & STF_SEMTOP) == 0)
621                         StmtFatalError(st, TOK_ERR_RESULT_SEQUENCING);
622                 st->st_ResStmt.es_ProcRetType =
623                                 resolveReturnType(st->st_MyGroup, flags);
624                 if (st->st_ResStmt.es_Exp) {
625                         st->st_ResStmt.es_Exp =
626                                 resolveExp(isg, st->st_MyGroup,
627                                            st->st_ResStmt.es_Exp,
628                                            st->st_ResStmt.es_ProcRetType,
629                                            RESOLVE_AUTOCAST);
630                 }
631
632                 /*
633                  * Flag that we executed result;
634                  */
635                 {
636                         Stmt *scan;
637                         for (scan = st; scan; scan = scan->st_Parent) {
638                                 scan->st_Flags |= STF_DIDRESULT;
639                                 scan->st_MyGroup->sg_Flags |= SGF_DIDRESULT;
640                                 if (scan->st_Flags & STF_SEMTOP)
641                                         break;
642                         }
643                 }
644                 break;
645         case ST_Switch:
646                 /*
647                  * NOTE: Switch type must be an rvalue.
648                  *
649                  * NOTE: It is possible to switch on a type.  See ST_Case
650                  *       below for more detail.
651                  */
652                 st->st_SwStmt.es_Exp->ex_Flags |= EXF_REQ_TYPE;
653                 st->st_SwStmt.es_Exp = resolveExp(isg, st->st_MyGroup,
654                                                   st->st_SwStmt.es_Exp,
655                                                   NULL, 0);
656
657                 /*
658                  * Switch-on-expression() expects an rvalue.
659                  */
660                 if ((st->st_SwStmt.es_Exp->ex_Flags & EXF_RET_TYPE) == 0) {
661                         st->st_SwStmt.es_Exp->ex_Type =
662                                 DEL_LVALUE(st->st_SwStmt.es_Exp->ex_Type);
663                 }
664                 {
665                         Stmt *scan;
666
667                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
668                                 resolveStmt(isg, scan, flags);
669                         }
670                 }
671                 break;
672         case ST_Case:
673                 /*
674                  * Handle a case/default.  Note that when switching on a type,
675                  * each case expression must return a type.
676                  *
677                  * NOTE: Case type must be an rvalue.  We use the switch type
678                  *       to cast, so it will be.
679                  */
680                 {
681                         Stmt *scan;
682                         Exp *exp;
683                         Type *type;
684
685                         /*
686                          * Set type to cast cases to if we are switching on
687                          * an expression, otherwise we are switching on a
688                          * type and should not try to coerce the cases (it
689                          * doesn't make sense to).
690                          */
691                         dassert_stmt(st, st->st_Parent->st_Op == ST_Switch);
692                         if (st->st_Parent->st_SwStmt.es_Exp->ex_Flags & EXF_RET_TYPE)
693                                 type = NULL;
694                         else
695                                 type = st->st_Parent->st_SwStmt.es_Exp->ex_Type;
696
697                         /*
698                          * case: (if es_Exp is NULL, this is a default: )
699                          */
700                         if ((exp = st->st_CaseStmt.es_Exp) != NULL) {
701                                 if (type == NULL)
702                                         exp->ex_Flags |= EXF_REQ_TYPE;
703                                 exp = resolveExp(isg, st->st_MyGroup,
704                                                  exp, type, RESOLVE_AUTOCAST);
705                                 if (type == NULL)
706                                         dassert(exp->ex_Flags & EXF_RET_TYPE);
707                                 st->st_CaseStmt.es_Exp = exp;
708                         }
709
710                         /*
711                          * Elements of the case/default
712                          */
713                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
714                                 resolveStmt(isg, scan, flags);
715                         }
716                 }
717                 break;
718         case ST_Exp:
719                 /*
720                  * NOTE: VoidType global implies an rvalue.
721                  *
722                  * NOTE: If resolveExp() doesn't cast to void for
723                  *       us, we will do it here.
724                  */
725                 {
726                         Exp *exp;
727
728                         exp = resolveExp(isg, st->st_MyGroup,
729                                          st->st_ExpStmt.es_Exp,
730                                          &VoidType, RESOLVE_AUTOCAST);
731                         if (exp->ex_Type != &VoidType) {
732                                 exp = resolveExpCast(isg, st->st_MyGroup,
733                                                      exp, &VoidType, flags);
734                         }
735                         st->st_ExpStmt.es_Exp = exp;
736                 }
737                 break;
738         case ST_Proc:
739                 {
740                         Stmt *scan;
741
742                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
743                                 resolveStmt(isg, scan, flags);
744                         }
745                 }
746                 break;
747         case ST_ThreadSched:
748                 break;
749         default:
750                 dassert_stmt(st, 0);
751         }
752         if (st->st_Flags & STF_SEMANTIC)
753                 resolvePopSGDepend(dep);
754 }
755
756 /*
757  * Locate the ST_Proc statement and resolve & return its return type
758  */
759 static
760 Type *
761 resolveReturnType(SemGroup *sg, int flags __unused)
762 {
763         Declaration *d;
764         Type *type;
765         Stmt *st;
766
767         /*
768          * Locate the ST_Proc statement
769          */
770         while (sg && (sg->sg_Stmt == NULL || sg->sg_Stmt->st_Op != ST_Proc))
771                 sg = sg->sg_Parent;
772         dassert(sg != NULL);
773         st = sg->sg_Stmt;
774         d = st->st_ProcStmt.es_Decl;    /* decl is already resolved */
775         dassert_decl(d, d->d_Op == DOP_PROC);
776         dassert_decl(d, d->d_Flags & (DF_RESOLVING|DF_RESOLVED));
777         type = d->d_ProcDecl.ed_Type;
778         dassert_decl(d, type->ty_Op == TY_PROC);
779         return(type->ty_ProcType.et_RetType);
780 }
781
782 Type *
783 resolveArgsType(SemGroup *sg, int flags __unused)
784 {
785         Declaration *d;
786         Type *type;
787         Stmt *st;
788
789         /*
790          * Locate the ST_Proc statement
791          */
792         while (sg && (sg->sg_Stmt == NULL || sg->sg_Stmt->st_Op != ST_Proc))
793                 sg = sg->sg_Parent;
794         dassert(sg != NULL);
795         st = sg->sg_Stmt;
796         d = st->st_ProcStmt.es_Decl;    /* decl is already resolved */
797         dassert_decl(d, d->d_Op == DOP_PROC);
798         dassert_decl(d, d->d_Flags & (DF_RESOLVING|DF_RESOLVED));
799         type = d->d_ProcDecl.ed_Type;
800         dassert_decl(d, type->ty_Op == TY_PROC);
801         return(type->ty_ProcType.et_ArgsType);
802 }
803
804 /*
805  * resolveDecl() - resolve a declaration
806  *
807  *      Note: we do not resolve d_Offset here.
808  *
809  *      If the declaration represents a procedure argument, special
810  *      processing of LVALUE scope is required to pass the declaration
811  *      by reference instead of by value.  Note that the size of the
812  *      underlying type DOES NOT CHANGE... it may be much larger.
813  */
814 void
815 resolveDecl(Declaration *d, int flags)
816 {
817         Type *type;
818         Stmt *st;
819         SemGroup *sg = NULL;
820
821         if (d->d_Flags & DF_RESOLVED)
822                 return;
823         dassert_decl(d, (d->d_Flags & DF_RESOLVING) == 0);
824         d->d_Flags |= DF_RESOLVING;
825
826         switch(d->d_Op) {
827         case DOP_CLASS:
828                 if (d->d_ClassDecl.ed_Super) {
829                         d->d_ClassDecl.ed_Super =
830                                 RESOLVETYPE(d->d_ClassDecl.ed_Super);
831                 }
832                 sg = d->d_ClassDecl.ed_SemGroup;
833                 if (resolveSemGroup1(sg, flags) && resolveSemGroup2(sg, flags))
834                         resolveSemGroup3(sg, flags);
835                 d->d_Bytes = d->d_ClassDecl.ed_SemGroup->sg_Bytes;
836                 d->d_AlignMask = d->d_ClassDecl.ed_SemGroup->sg_AlignMask;
837                 break;
838         case DOP_ALIAS:
839                 /*
840                  * Alias access is a barrier and always returns an rvalue.
841                  */
842                 type = d->d_AliasDecl.ed_Type =
843                                 RESOLVETYPE(d->d_AliasDecl.ed_Type);
844                 if (d->d_AliasDecl.ed_AssExp) {
845                         d->d_AliasDecl.ed_AssExp =
846                                 resolveExp(d->d_ImportSemGroup, d->d_MyGroup,
847                                            d->d_AliasDecl.ed_AssExp,
848                                            DEL_LVALUE(type),
849                                            flags | RESOLVE_AUTOCAST);
850                 }
851                 /* handled in DOT and STRIND resolver */
852                 SetDupExp(NULL, d->d_AliasDecl.ed_AssExp);
853                 break;
854         case DOP_TYPEDEF:
855                 d->d_Flags |= DF_RESOLVED;
856                 type = RESOLVETYPE(d->d_TypedefDecl.ed_Type); 
857                 d->d_Flags &= ~DF_RESOLVED;
858                 d->d_TypedefDecl.ed_Type = type;
859                 break;
860         case DOP_IMPORT:
861                 /*
862                  * This only occurs when resolving an import's semantic group.
863                  * Since we are scanning statements in that context we do not
864                  * have to recurse here, resolveStmt() will do it for us.
865                  */
866                 break;
867         case DOP_PROC:
868                 /*
869                  * XXX global procedure, later on, make the argument a
870                  * type instead of storage?
871                  */
872                 d->d_ProcDecl.ed_Type = RESOLVETYPE(d->d_ProcDecl.ed_Type);
873
874                 /*
875                  * Deal with constructor/destructor chaining.  The chaining
876                  * winds up being reversed and will be corrected by the caller.
877                  */
878                 if (d->d_ScopeFlags & SCOPE_GLOBAL) {
879                         if ((d->d_Flags & DF_ONGLIST) == 0 &&
880                             (d->d_ScopeFlags & (SCOPE_CONSTRUCTOR |
881                                                SCOPE_DESTRUCTOR))) {
882                                 d->d_GNext = d->d_MyGroup->sg_GBase;
883                                 d->d_MyGroup->sg_GBase = d;
884                                 d->d_Flags |= DF_ONGLIST;
885                         }
886                 } else {
887                         if ((d->d_Flags & DF_ONCLIST) == 0 &&
888                             (d->d_ScopeFlags & SCOPE_CONSTRUCTOR)) {
889                                 d->d_CNext = d->d_MyGroup->sg_CBase;
890                                 d->d_MyGroup->sg_CBase = d;
891                                 d->d_Flags |= DF_ONCLIST;
892                         }
893                         if ((d->d_Flags & DF_ONDLIST) == 0 &&
894                             (d->d_ScopeFlags & SCOPE_DESTRUCTOR)) {
895                                 d->d_DNext = d->d_MyGroup->sg_DBase;
896                                 d->d_MyGroup->sg_DBase = d;
897                                 d->d_Flags |= DF_ONDLIST;
898                         }
899                 }
900
901                 /*
902                  * If this procedure is bound to a DLL we have to resolve
903                  * it here.
904                  */
905                 if (d->d_ScopeFlags & SCOPE_CLANG) {
906                         d->d_ProcDecl.ed_DLLFunc = 
907                                 FindDLLSymbol(NULL, d->d_ImportSemGroup,
908                                               d->d_Id);
909                 }
910                 break;
911         case DOP_ARGS_STORAGE:
912         case DOP_STACK_STORAGE:
913         case DOP_GLOBAL_STORAGE:
914         case DOP_GROUP_STORAGE:
915                 type = RESOLVETYPE(d->d_StorDecl.ed_Type);
916                 d->d_StorDecl.ed_Type = type;
917
918                 /*
919                  * Promote the lvalue storage qualifier (e.g. from a typedef)
920                  * into the declaration's scope.  This is what ultimately
921                  * controls lvalue vs rvalue arguments to procedures and such.
922                  */
923                 if ((type->ty_SQFlags & SF_LVALUE) && 
924                     (d->d_ScopeFlags & SCOPE_LVALUE) == 0
925                 ) {
926                         d->d_ScopeFlags |= SCOPE_LVALUE;
927                 }
928
929                 /*
930                  * Default assignment handling expects an rvalue.
931                  */
932                 if (d->d_StorDecl.ed_AssExp) {
933                         d->d_StorDecl.ed_AssExp =
934                                 resolveExp(d->d_ImportSemGroup, d->d_MyGroup,
935                                            d->d_StorDecl.ed_AssExp,
936                                            DEL_LVALUE(type),
937                                            flags | RESOLVE_AUTOCAST);
938                 }
939                 if (d->d_ScopeFlags & SCOPE_LVALUE) {
940                         /*
941                          * Object is passed as a LValueStor structure.  Note
942                          * that d_Bytes is going to be different then the
943                          * underlying type (which represents the actual
944                          * object).
945                          */
946                         d->d_Bytes = sizeof(LValueStor);
947                         d->d_AlignMask = LVALUE_ALIGN;
948                 } else { 
949                         /*
950                          * Object is passed by value.
951                          */
952                         d->d_AlignMask = type->ty_AlignMask;
953                         d->d_Bytes = type->ty_Bytes;
954                 }
955
956                 /*
957                  * If the declaration represents or contains an
958                  * argument-lvalue or a pointer we have to add it to
959                  * the SemGroup's SRBase list to properly reference or
960                  * dereference the elements.  XXX only do this for non-global
961                  * storage.
962                  *
963                  * If the declaration has LVALUE scope we must do the same
964                  * because the ref is tracked.
965                  */
966                 if (d->d_Op != DOP_GLOBAL_STORAGE &&
967                     (type->ty_Flags & TF_HASLVPTR)) {
968                         d->d_SRNext = d->d_MyGroup->sg_SRBase;
969                         d->d_MyGroup->sg_SRBase = d;
970                 } else if (d->d_ScopeFlags & SCOPE_LVALUE) {
971                         d->d_SRNext = d->d_MyGroup->sg_SRBase;
972                         d->d_MyGroup->sg_SRBase = d;
973                 }
974
975                 /*
976                  * Deal with constructor/destructor chaining.  The chaining
977                  * winds up being reversed and will be corrected by the
978                  * caller.
979                  */
980                 if (type->ty_Flags & TF_HASCONSTRUCT) {
981                         d->d_CNext = d->d_MyGroup->sg_CBase;
982                         d->d_MyGroup->sg_CBase = d;
983                 }
984                 if (type->ty_Flags & TF_HASDESTRUCT) {
985                         d->d_DNext = d->d_MyGroup->sg_DBase;
986                         d->d_MyGroup->sg_DBase = d;
987                 }
988                 if (type->ty_Flags & (TF_HASGCONSTRUCT|TF_HASGDESTRUCT)) {
989                         d->d_GNext = d->d_MyGroup->sg_GBase;
990                         d->d_MyGroup->sg_GBase = d;
991                 }
992
993                 /*
994                  * We set content-locking defaults generically.  With no
995                  * SCOPE_* flags set the default will be normally-locked
996                  * (GENSTAT_LOCK).  SCOPE_UNLOCKED means GENSTAT_REFD
997                  * (content is always at least referenced), SCOPE_HARD
998                  * is for hard-locking (GENSTAT_LOCKH).
999                  *
1000                  * Content-locking is only applicable to an lvalue,
1001                  * pointer, or reference object, but we still want to
1002                  * set the proper defaults more generically.
1003                  *
1004                  * The contents of classes and arrays are never content-
1005                  * locked.  Compound types (that are not procedure arguments)
1006                  * are also not content-locked for now.
1007                  */
1008                 if ((d->d_Op & DOPF_STORAGE) &&
1009                     (d->d_Scope.s_Flags & SCOPE_LVALUE) == 0) {
1010                         if (type->ty_Op == TY_CLASS ||
1011                             type->ty_Op == TY_ARYOF ||
1012                             type->ty_Op == TY_COMPOUND) {
1013                                 d->d_ScopeFlags |= SCOPE_UNLOCKED;
1014                         }
1015                 }
1016
1017                 break;
1018         default:
1019                 dassert_decl(d, 0);
1020         }
1021         d->d_Flags &= ~DF_RESOLVING;
1022         d->d_Flags |= DF_RESOLVED;
1023
1024         /*
1025          * Post resolution flag resolving (to handle recursion)
1026          */
1027         switch(d->d_Op) {
1028         case DOP_PROC:
1029                 /*
1030                  * Create copies of procedures as they are needed (thus
1031                  * avoiding an XxY matrix effect).
1032                  */
1033                 if ((st = d->d_ProcDecl.ed_OrigBody) == NULL) {
1034                         Declaration *super = d->d_Super;
1035                         while (super && super->d_ProcDecl.ed_OrigBody == NULL) {
1036                                 super = super->d_Super;
1037                         }
1038                         if (super) {
1039                                 st = super->d_ProcDecl.ed_OrigBody;
1040                                 if (super->d_MyGroup->sg_Stmt->st_Op == ST_Class) {
1041                                         /*
1042                                          * Copy-down a procedure from a
1043                                          * superclass.  The procedure must
1044                                          * still be linked into its superclass
1045                                          * for semantic searches to work as
1046                                          * expected, hence the use of super->
1047                                          * d_MyGroup and st->st_Parent.
1048                                          *
1049                                          * Note that this code is not reached
1050                                          * in the case of a nested procedure,
1051                                          * since nested procedures are copied
1052                                          * with the parent.
1053                                          */
1054                                         st = DupStmt(super->d_MyGroup,
1055                                                      st->st_Parent, st);
1056                                 } else {
1057                                         /*
1058                                          * Copy-down a nested procedure.
1059                                          * The procedure must be linked
1060                                          * into the copy of the parent
1061                                          * prodedure, not the original
1062                                          * parent procedure, or it will
1063                                          * never be resolved.
1064                                          */
1065                                         st = DupStmt(d->d_Stmt->st_MyGroup,
1066                                                      d->d_Stmt, st);
1067                                 }
1068                         } else {
1069                                 /*
1070                                  * Internal procedure (we do not need to do
1071                                  * anything), there is no statement body
1072                                  * to duplicate.
1073                                  */
1074                         }
1075                 } else {
1076                         /*
1077                          * Procedure is being used in the primary class it
1078                          * was defined in.
1079                          */
1080                         st = DupStmt(d->d_MyGroup, st->st_Parent, st);
1081                 }
1082                 if (st) {
1083                         /*
1084                          * Link the procedure body to the declaration and
1085                          * resolve the procedure body.
1086                          */
1087                         dassert_stmt(st, d->d_ProcDecl.ed_ProcBody == NULL);
1088
1089                         d->d_ProcDecl.ed_ProcBody = st;
1090                         st->st_ProcStmt.es_Decl = d;
1091                         st->st_ProcStmt.es_Scope = d->d_Scope;
1092                         resolveStmt(d->d_ImportSemGroup, st, flags);
1093 #if 0
1094                         ResolveAlignment(st, flags);
1095                         ResolveStorage(st, flags);
1096 #endif
1097                 }
1098                 break;
1099         default:
1100                 break;
1101         }
1102
1103         /*
1104          * __align(%d) scope qualifier, override the type's alignment
1105          */
1106         if ((d->d_Scope.s_Flags & SCOPE_ALIGN) && d->d_Scope.s_AlignOverride)
1107                 d->d_AlignMask = d->d_Scope.s_AlignOverride - 1;
1108 }
1109
1110 /*
1111  * resolveExp() - resolve expression
1112  *
1113  * Resolve an expression.  We are expected to resolve all ex_Type's 
1114  * for the expression tree as well as expected to track down
1115  * operators and base identifiers.
1116  *
1117  * itype is a type hint.  If non-NULL, the caller would like our
1118  * expression to return the specified type.  There are a few special
1119  * cases:
1120  *
1121  * EXF_REQ_ARRAY - when OBRACKET requests an arry optimization it
1122  *                 passes a post-array-indexed typehint (as if
1123  *                 you had done the optimization).  You must ignore
1124  *                 itype if you are unable to do the optimization.
1125  *
1126  * NOTE: Even rvalues may have refstor side-effects at run-time.
1127  */
1128 Exp *
1129 resolveExp(SemGroup *isg, SemGroup *sg, Exp *exp, Type *itype, int flags)
1130 {
1131         Exp copy;
1132         int couldconst;
1133
1134         loadExpCopy(&copy, exp);
1135         couldconst = 0;
1136
1137         /*
1138          * Must resolve cast target type hint.
1139          */
1140         if (itype)
1141                 itype = RESOLVETYPE(itype);
1142
1143         /*
1144          * note: certain cases below call other resolver functions and assume
1145          * that ex* variables are unchanged.
1146          */
1147         dassert((exFlags & EXF_DUPEXP) || (exFlags & EXF_RESOLVED) == 0);
1148
1149         switch(exToken) {
1150         case TOK_ASS:
1151                 /*
1152                  * An assignment.  Note that we optimize void returns
1153                  * (such as when an assignment is a statement like 'a = 4;'
1154                  * ... the result of the assignment is cast to void.
1155                  *
1156                  * NOTE: Left-hand-side must be an LVALUE, return type
1157                  *       inherits this feature unless the parent turns off
1158                  *       the bit so the TOK_ASS run-time must deal with that.
1159                  */
1160                 exLhs = resolveExp(isg, sg, exLhs, NULL,
1161                                    flags & ~RESOLVE_AUTOCAST);
1162                 dassert_exp(exLhs, exLhs->ex_Type->ty_SQFlags & SF_LVALUE);
1163
1164                 exRhs = resolveExp(isg, sg, exRhs,
1165                                    DEL_LVALUE(exLhs->ex_Type),
1166                                    flags | RESOLVE_AUTOCAST);
1167                 if (exLhs->ex_Type->ty_SQFlags & SF_CONST) {
1168                         ExpFatalError(exp, TOK_ERR_READONLY);
1169                 }
1170
1171                 /* AssExp handles this optimization */
1172                 if (itype == &VoidType) {
1173                         exType = itype;
1174                         exFlags |= EXF_RET_VOID;
1175                 } else {
1176                         exType = exLhs->ex_Type;
1177                 }
1178
1179 #if 0
1180                 /*
1181                  * Check @ref assignment compatibility.
1182                  */
1183                 if (exLhs->ex_Type->ty_Op == TY_REFTO) {
1184                         switch(MatchType(exLhs->ex_Type, exRhs->ex_Type)) {
1185                         case SG_COMPAT_FULL:
1186                                 printf("assign %s compatibility FULL\n",
1187                                         exLhs->ex_Id);
1188                                 break;
1189                         case SG_COMPAT_PART:
1190                                 printf("assign %s compatibility PART\n",
1191                                         exLhs->ex_Id);
1192                                 break;
1193                         case SG_COMPAT_SUBCLASS:
1194                                 printf("assign %s compatibility SUBCL\n",
1195                                         exLhs->ex_Id);
1196                                 break;
1197                         case SG_COMPAT_FAIL:
1198                                 printf("assign %s compatibility FAIL\n",
1199                                         exLhs->ex_Id);
1200                                 break;
1201                         }
1202                 }
1203 #endif
1204                 break;
1205         case TOK_ANDAND:
1206                 /*
1207                  * NOTE: BoolType global implies an rvalue.
1208                  */
1209                 couldconst = 1;
1210                 exLhs = resolveExp(isg, sg, exLhs, &BoolType,
1211                                    flags | RESOLVE_AUTOCAST);
1212
1213                 /*
1214                  * If left-side can terminate the operation, mark the
1215                  * expression as PROBCONST for the interpreter and code
1216                  * generator (allowing the rhs to not be a constant).
1217                  */
1218                 if (exLhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)) {
1219                         RunTmpStor ts;
1220
1221                         exLhs = resolveConstExpBool(isg, sg, exLhs, flags, &ts);
1222                         if (ts.ts_Bool == 0)
1223                                 exFlags |= EXF_PROBCONST;
1224                 }
1225
1226                 /*
1227                  * Resolve rhs, and we can also flag PROBCONST if both sides
1228                  * are constants.
1229                  */
1230                 exRhs = resolveExp(isg, sg, exRhs, &BoolType,
1231                                    flags | RESOLVE_AUTOCAST);
1232                 if ((exLhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)) &&
1233                     (exRhs->ex_Flags & (EXF_CONST | EXF_PROBCONST))) {
1234                         exFlags |= EXF_PROBCONST;
1235                 }
1236                 exType = &BoolType;
1237                 break;
1238         case TOK_OROR:
1239                 /*
1240                  * NOTE: BoolType global implies an rvalue.
1241                  */
1242                 couldconst = 1;
1243                 exLhs = resolveExp(isg, sg, exLhs, &BoolType,
1244                                    flags | RESOLVE_AUTOCAST);
1245
1246                 /*
1247                  * If left-side can terminate the operation, mark the
1248                  * expression as PROBCONST for the interpreter and code
1249                  * generator (allowing the rhs to not be a constant).
1250                  */
1251                 if (exLhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)) {
1252                         RunTmpStor ts;
1253
1254                         exLhs = resolveConstExpBool(isg, sg, exLhs, flags, &ts);
1255                         if (ts.ts_Bool)
1256                                 exFlags |= EXF_PROBCONST;
1257                 }
1258
1259                 /*
1260                  * Resolve rhs, and we can also flag PROBCONST if both sides
1261                  * are constants.
1262                  */
1263                 exRhs = resolveExp(isg, sg, exRhs, &BoolType,
1264                                    flags | RESOLVE_AUTOCAST);
1265                 if ((exLhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)) &&
1266                     (exRhs->ex_Flags & (EXF_CONST | EXF_PROBCONST))) {
1267                         exFlags |= EXF_PROBCONST;
1268                 }
1269                 exType = &BoolType;
1270                 break;
1271         case TOK_DECL:
1272                 /*
1273                  * This synthesized token occurs when we are able to collapse
1274                  * a structural indirection or dotted element into a
1275                  * declaration.  For example, 'module.routine'.
1276                  */
1277                 /* XXX couldconst? */
1278                 break;
1279         case TOK_DOT:
1280         case TOK_STRIND:
1281                 /*
1282                  * Structual field access.  The left hand side may be an object
1283                  * (class or compound), a class type, or a compound type.
1284                  * 
1285                  * A dotted access requires an lvalue on the left hand side
1286                  * if the left hand side represents storage.
1287                  *
1288                  * The result will be an lvalue if the right hand side
1289                  * represents storage.  We only loop if the right hand side
1290                  * is an alias replacement.
1291                  */
1292                 {
1293                         string_t id;
1294                         Declaration *d;
1295                         SemGroup *sg2;
1296                         Type *type;
1297                         int globalOnly = 0;
1298                         int s;
1299                         int visibility;
1300                         int isRefTo = 0;
1301                         int procedureOnly = 0;
1302                         int eno = TOK_ERR_ID_NOT_FOUND;
1303
1304                         /*
1305                          * NOTE: Hint must 'always happen' since we may be
1306                          *       modifying an expression that will later be
1307                          *       Dup'd.
1308                          *
1309                          * NOTE: Lhs is always an lvalue for TOK_DOT, but
1310                          *       does not have to be for TOK_STRIND.
1311                          */
1312                         exLhs->ex_Flags |= EXF_REQ_TYPE;
1313                         if (exToken == TOK_DOT) {
1314                                 exLhs->ex_Flags |=
1315                                     exFlags & (EXF_REQ_ADDROF | EXF_ADDRUSED);
1316                         }
1317                         exLhs = resolveExp(isg, sg, exLhs, NULL,
1318                                            flags & ~RESOLVE_AUTOCAST);
1319
1320                         /*
1321                          * The RHS may have been turned into a TOK_SEMGRP_ID
1322                          * in a previous duplicate.  The change is considered
1323                          * permanent.
1324                          */
1325                         if (exRhs->ex_Token != TOK_SEMGRP_ID) {
1326                                 dassert_exp(exRhs,
1327                                             exRhs->ex_Token == TOK_STRUCT_ID);
1328                                 exRhs = resolveExp(isg, sg, exRhs, NULL,
1329                                                    flags & ~RESOLVE_AUTOCAST);
1330                         }
1331                         id = exRhs->ex_Id;
1332                         type = exLhs->ex_Type;
1333
1334                         /*
1335                          * Calculate scope and SemGroup to search.  Note
1336                          * that it is legal to do a structural '.' selection
1337                          * on a pointer, but it works differently then
1338                          * indirecting through a pointer via '->'.  In the
1339                          * case of '.' on a pointer, we first search the
1340                          * system Pointer class.
1341                          */
1342                         if (exLhs->ex_Flags & EXF_RET_TYPE) {
1343                                 globalOnly = 1;
1344                         }
1345
1346                         /*
1347                          * Figure out the base type used to look-up the
1348                          * identifier.  An identifier that resolves into a
1349                          * procedure winds up only being a hint for a
1350                          * reference type.
1351                          */
1352                         if (exToken == TOK_STRIND) {
1353                                 switch(type->ty_Op) {
1354                                 case TY_CPTRTO:
1355                                         type = type->ty_CPtrType.et_Type;
1356                                         break;
1357                                 case TY_PTRTO:
1358                                         type = type->ty_PtrType.et_Type;
1359                                         break;
1360                                 case TY_REFTO:
1361                                         type = type->ty_RefType.et_Type;
1362                                         isRefTo = 1;
1363                                         break;
1364                                 default:
1365                                         dassert_exp(exp, 0);
1366                                         /* not reached */
1367                                 }
1368                         }
1369
1370 again:
1371                         switch(type->ty_Op) {
1372                         case TY_CLASS:
1373                                 sg2 = type->ty_ClassType.et_SemGroup;
1374                                 break;
1375                         case TY_COMPOUND:
1376                                 sg2 = type->ty_CompType.et_SemGroup;
1377                                 break;
1378                         case TY_ARGS:
1379                                 sg2 = type->ty_ArgsType.et_SemGroup;
1380                                 break;
1381                         case TY_VAR:
1382                                 sg2 = type->ty_VarType.et_SemGroup;
1383                                 break;
1384                         case TY_IMPORT:
1385                                 sg2 = type->ty_ImportType.et_SemGroup;
1386                                 break;
1387                         case TY_CPTRTO:
1388                                 /* YYY */
1389                                 dassert_exp(exp, PointerType.ty_Op == TY_CLASS);
1390                                 sg2 = PointerType.ty_ClassType.et_SemGroup;
1391                                 break;
1392                         case TY_PTRTO:
1393                                 dassert_exp(exp, PointerType.ty_Op == TY_CLASS);
1394                                 sg2 = PointerType.ty_ClassType.et_SemGroup;
1395                                 break;
1396                         case TY_REFTO:
1397                                 /* YYY */
1398                                 dassert_exp(exp, PointerType.ty_Op == TY_CLASS);
1399                                 sg2 = PointerType.ty_ClassType.et_SemGroup;
1400                                 break;
1401                         default:
1402                                 /*
1403                                  * Possibly a pointer, aka ptr.NULL
1404                                  */
1405                                 sg2 = NULL;
1406                         }
1407                         visibility = exLhs->ex_Visibility;
1408
1409                         /*
1410                          * Locate the identifier normally, via its type.
1411                          * ty_TypeVisbility is the initial visibility (scope)
1412                          * that the semantic search should use in locating
1413                          * the identifier.
1414                          */
1415                         if (sg2) {
1416                                 string_t ary[2] = { id, NULL };
1417                                 int level;
1418
1419                                 if (exLhs->ex_Token == TOK_ID ||
1420                                     exLhs->ex_Token == TOK_DECL) {
1421                                         if (exLhs->ex_Decl->d_Search) {
1422                                                 level = exLhs->ex_Decl->
1423                                                          d_Search->sg_Level;
1424                                         } else {
1425                                                 level = sg2->sg_Level;
1426                                         }
1427
1428                                         /*
1429                                          * XXX BIG HACK
1430                                          */
1431                                         if (exLhs->ex_Flags & EXF_SUPER) {
1432                                                 if (isRefTo) {
1433                                                         fprintf(stderr, "Can't super with reference type\n");
1434                                                         dassert_exp(exp, 0);
1435                                                 }
1436                                                 if (level == 0) {
1437                                                         fprintf(stderr, "No superclass available\n");
1438                                                         dassert_exp(exp, 0);
1439                                                 }
1440                                                 --level;
1441                                         }
1442                                 } else {
1443                                         level = sg2->sg_Level;  /* may be -1 */
1444                                 }
1445                                 visibility &= type->ty_Visibility;
1446                                 d = FindDeclPath(&exp->ex_LexRef, NULL,
1447                                                  sg2, NULL,
1448                                                  ary, FDC_NOBACK,
1449                                                  &visibility, level, &eno);
1450                                 /*
1451                                  * XXX more hack.  If the super is visible
1452                                  * and a procedure we just found our own
1453                                  * refinement, not the superclass method.
1454                                  * This is because there is no 'superclass
1455                                  * method' per say, refinements *REPLACE*
1456                                  * superclass declarations and inherit the
1457                                  * superclass's level.  However, we still
1458                                  * want to be able to chain method calls so
1459                                  * what we do instead is go through and find
1460                                  * the procedure that we smacked when we did
1461                                  * the refinement.  This procedure has
1462                                  * already been conveniently brought into
1463                                  * the subclass context as an 'invisible'
1464                                  * entity at the same d_Level.
1465                                  */
1466                                 if ((exLhs->ex_Flags & EXF_SUPER) &&
1467                                     d &&
1468                                     d->d_Op == DOP_PROC &&
1469                                     (d->d_ScopeFlags & SCOPE_ALL_VISIBLE)
1470                                 ) {
1471                                         string_t id2 = d->d_Id;
1472                                         SemGroup *olevel = d->d_Level;
1473
1474                                         dassert_exp(exp, isRefTo == 0);
1475
1476                                         while ((d = RUNE_NEXT(d, d_Node)) != NULL) {
1477                                                 if (d->d_Id == id2 &&
1478                                                     d->d_Level == olevel && 
1479                                                     d->d_Op == DOP_PROC) {
1480                                                         break;
1481                                                 }
1482                                         }
1483                                 }
1484                         } else {
1485                                 d = NULL;
1486                         }
1487
1488                         if (d && procedureOnly && d->d_Op != DOP_PROC) {
1489                                 fprintf(stderr,
1490                                         "PTR.ELEMENT may be used for special "
1491                                         "pointer method calls, but not to "
1492                                         "access storage elements.  "
1493                                         "Use PTR->ELEMENT instead\n");
1494                                 dassert_exp(exp, 0);
1495                         }
1496
1497                         /*
1498                          * If referencing actual storage the storage must be
1499                          * declared global.
1500                          */
1501                         if (d && globalOnly && (d->d_Op & DOPF_STORAGE) &&
1502                                 (d->d_ScopeFlags & SCOPE_GLOBAL) == 0
1503                         ) {
1504                                 fprintf(stderr,
1505                                         "%s is not global.  Only globals "
1506                                         "can be accessed through a type\n",
1507                                         d->d_Id);
1508                                 dassert_exp(exp, 0);
1509                         }
1510
1511                         if (d) {
1512                                 /*
1513                                  * Identifier found.  Note that if we are
1514                                  * going through a reference type the
1515                                  * declaration is not the actual one we 
1516                                  * use at run time.  It's just a template.
1517                                  */
1518                                 resolveDecl(d, flags);
1519                                 exDecl = d;
1520                                 exVisibility = visibility;
1521
1522                                 /*
1523                                  * XXX this is in wrong place
1524                                  *
1525                                  * ADDROF content-locked storage is not
1526                                  * allowed, except for the SCOPE_LVALUE case
1527                                  * if the underlying type is acceptable.
1528                                  *
1529                                  * If we are running through an LValueStor
1530                                  * UNLOCKED applies to it and not its contents.
1531                                  * Check to see if the contents are acceptable.
1532                                  */
1533                                 if ((exFlags & EXF_REQ_ADDROF) &&
1534                                     (d->d_Op & DOPF_STORAGE) &&
1535                                    (d->d_Scope.s_Flags & SCOPE_UNLOCKED) == 0) {
1536                                         type = d->d_StorDecl.ed_Type;
1537                                         if ((type->ty_Flags & TF_HASLVPTR) && 
1538                                             type->ty_Op != TY_CLASS &&
1539                                             type->ty_Op != TY_ARYOF) {
1540                                                 ExpFatalError(exp,
1541                                                     TOK_ERR_ILLEGAL_ADDRLOCKED);
1542                                         }
1543                                 }
1544
1545                                 /*
1546                                  * Misc.
1547                                  */
1548                                 switch(d->d_Op) {
1549                                 case DOP_PROC:
1550                                         exType = d->d_ProcDecl.ed_Type;
1551                                         if (d->d_ProcDecl.ed_Type->ty_SQFlags & SF_METHOD) {
1552                                                 /*
1553                                                  * Method call, do not
1554                                                  * collapse the expression into
1555                                                  * a direct declaration because
1556                                                  * the object is needed later.
1557                                                  */
1558                                                 if (exLhs->ex_Flags & EXF_RET_TYPE)
1559                                                         ExpPrintError(exLhs, TOK_ERR_METHOD_REQUIRES_OBJ);
1560                                                 dassert((exLhs->ex_Flags & EXF_RET_TYPE) == 0);
1561                                         } else if (isRefTo) {
1562                                                 /*
1563                                                  * Call via reference.  The
1564                                                  * lhs is required to evaluate
1565                                                  * the actual method call at
1566                                                  * run-time.
1567                                                  */
1568                                         } else {
1569                                                 /*
1570                                                  * Global method call or normal
1571                                                  * call.  For the global method
1572                                                  * case the lhs is not needed
1573                                                  * because the parser entered
1574                                                  * the first argument as a
1575                                                  * type already.
1576                                                  *
1577                                                  * Degenerate into a TOK_DECL.
1578                                                  * We depend on this later.
1579                                                  */
1580                                                 exFlags &= ~EXF_BINARY;
1581                                                 exLhs = NULL;
1582                                                 exRhs = NULL;
1583                                                 exToken = TOK_DECL;
1584                                         }
1585                                         break;
1586                                 case DOP_ALIAS:
1587                                         exType = DEL_LVALUE(d->d_AliasDecl.ed_Type);
1588                                         dassert_decl(d, d->d_AliasDecl.ed_AssExp != NULL);
1589                                         /*
1590                                          * NOTE: exLhs must be NULL if exp is
1591                                          * unresolved.  exp tree duplications
1592                                          * do not duplicate the alias's exLHS
1593                                          * even though UNARY is set.
1594                                          */
1595                                         dassert_exp(exp, exRhs->ex_Lhs == NULL);
1596                                         exRhs->ex_Flags |= EXF_ALIAS | EXF_UNARY;
1597                                         exRhs->ex_Lhs = DupExp(sg2,
1598                                                            d->d_AliasDecl.ed_AssExp);
1599                                         exRhs->ex_Lhs = resolveExp(isg, sg2,
1600                                                                 exRhs->ex_Lhs,
1601                                                                 exType,
1602                                                                 flags | RESOLVE_AUTOCAST);
1603                                         break;
1604                                 case DOP_ARGS_STORAGE:
1605                                 case DOP_STACK_STORAGE:
1606                                 case DOP_GLOBAL_STORAGE:
1607                                 case DOP_GROUP_STORAGE:
1608                                         /*
1609                                          * Set type.  The Rhs is a STRUCT_ID
1610                                          * and does not require a type to be
1611                                          * assigned to it.
1612                                          *
1613                                          * Return type is always an LVALUE,
1614                                          * parent may adjust.
1615                                          */
1616                                         exType = ADD_LVALUE(d->d_StorDecl.ed_Type);
1617
1618                                         /*
1619                                          * Pull up global constants
1620                                          */
1621                                         if (exToken == TOK_DOT &&
1622                                             d->d_Op == DOP_GLOBAL_STORAGE &&
1623                                             (d->d_ScopeFlags & SCOPE_CONSTANT) &&
1624                                             (exLhs->ex_Flags & EXF_RET_TYPE)) {
1625                                                 exFlags |= EXF_PROBCONST;
1626                                         }
1627                                         break;
1628                                 case DOP_TYPEDEF:
1629                                         /*
1630                                          * XXX make sure this is only used
1631                                          * in the lhs of a structural
1632                                          * reference. XXX
1633                                          *
1634                                          * XXX what if we went through a
1635                                          * TY_RETO type?  This type will
1636                                          * be wrong.
1637                                          *
1638                                          * collapse the exp node.
1639                                          */
1640                                         exType = d->d_TypedefDecl.ed_Type;
1641                                         exToken = TOK_DECL;
1642                                         exFlags &= ~EXF_BINARY;
1643                                         break;
1644                                 case DOP_IMPORT:
1645                                         /*
1646                                          * Do not collapse an import, we
1647                                          * require more resolution.  e.g.
1648                                          * import.<blah> will be collapsed,
1649                                          * but 'import' cannot be.
1650                                          */
1651                                         if (exFlags & EXF_REQ_TYPE) {
1652                                                 exType =
1653                         AllocImportType(
1654                                 &d->d_ImportDecl.ed_SemGroup->sg_ClassList,
1655                                 d->d_ImportDecl.ed_SemGroup,
1656                                 visibility);
1657                                                 exFlags |= EXF_RET_TYPE;
1658                                                 break;
1659                                         }
1660                                         break;
1661                                 case DOP_CLASS:
1662                                         /*
1663                                          * Do not collapse a class, we require
1664                                          * more resolution.  e.g. class.<blah>
1665                                          * will be collapsed, but 'class'
1666                                          * cannot be.
1667                                          */
1668                                         if (exFlags & EXF_REQ_TYPE) {
1669                                                 exType =
1670                         AllocClassType(
1671                                 &d->d_ClassDecl.ed_SemGroup->sg_ClassList,
1672                                 d->d_ClassDecl.ed_Super,
1673                                 d->d_ClassDecl.ed_SemGroup,
1674                                 visibility);
1675                                                 exFlags |= EXF_RET_TYPE;
1676                                                 break;
1677                                         }
1678                                         break;
1679                                 default:
1680                                         dassert_exp(exp, 0);
1681                                         break;
1682                                 }
1683                                 if (d->d_Op == DOP_PROC) {
1684                                         if (d->d_ScopeFlags & SCOPE_PURE)
1685                                                 couldconst = 1;
1686                                 } else if (exType->ty_SQFlags & SF_CONST) {
1687                                         couldconst = 1;
1688                                 }
1689
1690                         } else if ((s = StrTableSpecial(id)) &
1691                                    SPECIALF_SEMGROUP) {
1692                                 /*
1693                                  * Identifier not found, check for a special
1694                                  * identifier.
1695                                  */
1696                                 exRhs->ex_Token = TOK_SEMGRP_ID;
1697                                 exRhs->ex_Int32 = s;
1698                                 exDecl = NULL;
1699
1700                                 switch(s) {
1701                                 case SPECIAL_NULL:
1702                                         dassert(type->ty_Op == TY_PTRTO || 
1703                                                 type->ty_Op == TY_REFTO ||
1704                                                 type->ty_Op == TY_CPTRTO);
1705                                         /* NULL is not an lvalue */
1706                                         exType = DEL_LVALUE(type);
1707                                         exFlags |= EXF_NULL;
1708                                         break;
1709                                 case SPECIAL_COUNT:
1710                                         dassert(type->ty_Op != TY_PTRTO && 
1711                                                 type->ty_Op != TY_REFTO &&
1712                                                 type->ty_Op != TY_CPTRTO);
1713                                         exType = &Int32Type;
1714                                         break;
1715                                 case SPECIAL_DATA:
1716                                         /*
1717                                          * typeof(self.__data[]) vs
1718                                          * (cast)self.__data[]
1719                                          */
1720                                         dassert(type->ty_Op != TY_PTRTO &&
1721                                                 type->ty_Op != TY_REFTO &&
1722                                                 type->ty_Op != TY_CPTRTO);
1723                                         dassert(exFlags & EXF_REQ_ARRAY);
1724                                         exFlags |= EXF_RET_ARRAY;
1725                                         if (exFlags & EXF_REQ_TYPE) {
1726                                                 exFlags |= EXF_RET_TYPE;
1727                                                 exType = &DynamicLValueType;
1728                                         } else if (itype) {
1729                                                 exType = itype;
1730                                         } else {
1731                                                 /*
1732                                                  * dynamic data must be cast
1733                                                  */
1734                                                 dassert_exp(exp, 0);
1735                                                 exType = &DynamicLValueType;
1736                                         }
1737                                         break;
1738                                 case SPECIAL_VAR_COUNT:
1739                                         dassert(type->ty_Op != TY_PTRTO &&
1740                                                 type->ty_Op != TY_REFTO &&
1741                                                 type->ty_Op != TY_CPTRTO);
1742                                         exType = &Int32Type;
1743                                         break;
1744                                 case SPECIAL_VAR_DATA:
1745                                         /*
1746                                          * typeof(self.__vardata[]) vs
1747                                          * (cast)self.__vardata[]
1748                                          */
1749                                         dassert(type->ty_Op != TY_PTRTO &&
1750                                                 type->ty_Op != TY_REFTO &&
1751                                                 type->ty_Op != TY_CPTRTO);
1752                                         dassert(exFlags & EXF_REQ_ARRAY);
1753                                         exFlags |= EXF_RET_ARRAY;
1754                                         if (exFlags & EXF_REQ_TYPE) {
1755                                                 exFlags |= EXF_RET_TYPE;
1756                                                 exType = &DynamicLValueType;
1757                                         } else if (itype) {
1758                                                 exType = itype;
1759                                         } else {
1760                                                 /*
1761                                                  * dynamic data must be cast
1762                                                  */
1763                                                 dassert_exp(exp, 0);
1764                                                 exType = &DynamicLValueType;
1765                                         }
1766                                         break;
1767                                 case SPECIAL_TYPEID:
1768                                         exType = &Int32Type;
1769                                         break;
1770                                 case SPECIAL_TYPESTR:
1771                                         exType = &StrType;
1772                                         break;
1773                                 default:
1774                                         dassert_exp(exRhs, 0);
1775                                         break;
1776                                 }
1777                         } else {
1778                                 /*
1779                                  * This is nasty, I admit.  If we have a
1780                                  * pointer or reference type try again.
1781                                  */
1782                                 exDecl = NULL;
1783                                 if (type->ty_Op == TY_PTRTO) {
1784                                         type = type->ty_PtrType.et_Type;
1785                                         procedureOnly = 1;
1786                                         goto again;
1787                                 }
1788                                 if (type->ty_Op == TY_REFTO) {
1789                                         type = type->ty_RefType.et_Type;
1790                                         procedureOnly = 1;
1791                                         goto again;
1792                                 }
1793                                 if (type->ty_Op == TY_CPTRTO) {
1794                                         type = type->ty_CPtrType.et_Type;
1795                                         procedureOnly = 1;
1796                                         goto again;
1797                                 }
1798                                 ExpFatalError(exRhs, eno);
1799                                 /* NOT REACHED */
1800                         }
1801                 }
1802                 dassert_exp(exp, exType != NULL);
1803                 break;
1804         case TOK_STRUCT_ID:
1805                 /*
1806                  * NOTE: unresolved identifiers should not have alias
1807                  *       expression sub-tree duplications attached to them.
1808                  *       assert it.
1809                  */
1810                 dassert_exp(exp, exLhs == NULL);
1811                 break;
1812         case TOK_OPER:
1813                 /*
1814                  * NOTE: LVALUE/RVALUE for elements and return type depends
1815                  *       on the operator.  Operator functions normally
1816                  *       self-optimize the cases at run-time.
1817                  */
1818                 couldconst = 1;
1819                 saveExpCopy(&copy, exp);
1820                 exp = resolveExpOper(isg, sg, exp, itype,
1821                                      flags & ~RESOLVE_AUTOCAST);
1822                 loadExpCopy(&copy, exp);
1823                 break;
1824         case TOK_PTRIND:
1825                 /*
1826                  * Indirect through an expression.
1827                  *
1828                  * Return type is typically an LVALUE (if representing
1829                  * storage).  Exp parent might turn it off so run-time
1830                  * must test.  Lhs may or may not be.
1831                  */
1832                 {
1833                         Type *type;
1834
1835                         exLhs = resolveExp(isg, sg, exLhs, NULL,
1836                                            flags & ~RESOLVE_AUTOCAST);
1837                         type = exLhs->ex_Type;
1838
1839                         switch(type->ty_Op) {
1840                         case TY_REFTO:
1841                                 if ((exFlags & EXF_INDREF) == 0) {
1842                                         fprintf(stderr, "You cannot use '*' on a reference type\n");
1843                                         dassert_exp(exLhs, 0);
1844                                 }
1845                                 exType = ADD_LVALUE(type->ty_RefType.et_Type);
1846                                 break;
1847                         case TY_PTRTO:
1848                                 exType = ADD_LVALUE(type->ty_PtrType.et_Type);
1849                                 break;
1850                         case TY_CPTRTO:
1851                                 exType = ADD_LVALUE(type->ty_CPtrType.et_Type);
1852                                 break;
1853                         default:
1854                                 dassert_exp(exLhs, 0);
1855                                 break;
1856                         }
1857                 }
1858                 break;
1859         case TOK_ADDR:
1860                 /*
1861                  * Take the address of an (LVALUE) expression.  Returns an
1862                  * RVALUE.   Allow for a short-cut optimization which replaces
1863                  * the TOK_ADDR sequence with its argument in the &ary[n]
1864                  * case.
1865                  */
1866                 {
1867                         Type *type;
1868
1869                         /*
1870                          * Hint must 'always happen' since we may be
1871                          * modifying an expression that will later be
1872                          * Dup'd.
1873                          *
1874                          * It is sufficient to test EXF_ADDRUSED to determine
1875                          * if SRSGET/SRSPUT is needed for the procedure.
1876                          */
1877                         exLhs->ex_Flags |= EXF_REQ_ADDROF | EXF_ADDRUSED;
1878                         exLhs = resolveExp(isg, sg, exLhs, NULL,
1879                                            flags & ~RESOLVE_AUTOCAST);
1880                         if (exLhs->ex_Flags & EXF_RET_ADDROF) {
1881                                 exp = exLhs;
1882                                 loadExpCopy(&copy, exp);
1883                         } else {
1884                                 type = exLhs->ex_Type;
1885                                 dassert_exp(exLhs,
1886                                             type->ty_SQFlags & SF_LVALUE);
1887                                 exType = RESOLVETYPE(TypeToPtrType(type));
1888                                 /* DEL_LVALUE() not needed here */
1889                         }
1890                 }
1891                 break;
1892         case TOK_OBRACKET:
1893                 /*
1894                  * Array index, takes an RVALUE, returns an LVALUE.
1895                  *
1896                  * Note: we have to convert the special __data[exp] case.
1897                  *
1898                  * Note: ex_Flags hints must 'always happen' since we may be
1899                  *       modifying an expression that will later be Dup'd.
1900                  */
1901                 exRhs = resolveExp(isg, sg, exRhs, NULL,
1902                                    flags & ~RESOLVE_AUTOCAST);
1903                 exLhs->ex_Flags |= EXF_REQ_ARRAY | (exFlags & EXF_REQ_TYPE);
1904                 exLhs->ex_Flags |= EXF_ADDRUSED;
1905                 exLhs->ex_AuxExp = exRhs;
1906                 exLhs = resolveExp(isg, sg, exLhs, itype,
1907                                    flags & ~RESOLVE_AUTOCAST);
1908
1909                 if (MatchType(&IntegralType, exRhs->ex_Type) <= SG_COMPAT_PART) {
1910                         ExpPrintError(exRhs, TOK_ERR_EXPECTED_INTEGRAL_TYPE);
1911                         dassert_exp(exp, 0);
1912                 }
1913
1914                 if (exLhs->ex_Flags & EXF_RET_ARRAY) {
1915                         /*
1916                          * __data and __vardata specials
1917                          */
1918                         exp->ex_Token = TOK_ERR_EXP_REMOVED;
1919                         return(exLhs);
1920                 } else if (exFlags & EXF_REQ_ADDROF) {
1921                         /*
1922                          * &ary[i] optimization - allows us to create
1923                          * a bounded pointer (returns an RVALUE).
1924                          */
1925                         Type *type;
1926
1927                         exFlags |= EXF_RET_ADDROF;
1928
1929                         dassert((exLhs->ex_Flags & EXF_RET_TYPE) == 0);
1930
1931                         exLhs->ex_AuxExp = NULL;
1932                         type = exLhs->ex_Type;
1933                         switch(type->ty_Op) {
1934                         case TY_ARYOF:
1935                                 type = type->ty_AryType.et_Type;
1936                                 break;
1937                         case TY_CPTRTO:
1938                                 type = type->ty_CPtrType.et_Type;
1939                                 break;
1940                         case TY_PTRTO:
1941                                 type = type->ty_PtrType.et_Type;
1942                                 break;
1943                         case TY_REFTO:
1944                                 /* Cannot take address of a reference type */
1945                                 dassert_exp(exp, 0);
1946                                 break;
1947                         }
1948                         exType = RESOLVETYPE(TypeToPtrType(type));
1949                         /* returns an RVALUE */
1950                 } else {
1951                         /*
1952                          * Unoptimized array lookup, returns an lvalue
1953                          */
1954                         Type *type;
1955
1956                         dassert((exLhs->ex_Flags & EXF_RET_TYPE) == 0);
1957
1958                         exLhs->ex_AuxExp = NULL;
1959                         type = exLhs->ex_Type;
1960                         switch(type->ty_Op) {
1961                         case TY_ARYOF:
1962                                 type = type->ty_AryType.et_Type;
1963                                 break;
1964                         case TY_CPTRTO:
1965                                 type = type->ty_CPtrType.et_Type;
1966                                 break;
1967                         case TY_PTRTO:
1968                                 type = type->ty_PtrType.et_Type;
1969                                 break;
1970                         case TY_REFTO:
1971                                 fprintf(stderr,
1972                                         "Cannot index a reference type\n");
1973                                 dassert_exp(exp, 0);
1974                                 break;
1975                         }
1976                         exType = ADD_LVALUE(type);
1977                         /* returns an LVALUE */
1978                 }
1979                 break;
1980         case TOK_OPAREN:
1981                 dassert_exp(exp, 0);    /* XXX */
1982                 break;
1983         case TOK_DSTRING:
1984         case TOK_BSTRING:
1985                 /*
1986                  * XXX we should return a bounded pointer here.
1987                  */
1988                 exType = &StrType;
1989                 exId = StrTableEscapeQuotedString(exId, strlen(exId), 1);
1990                 ReplaceStrTable(&exp->ex_Id, exId);
1991                 break;
1992         case TOK_SSTRING:
1993                 couldconst = 1;
1994                 exFlags |= EXF_CONST;
1995                 exType = &UInt8Type;    /* XXX make wide? */
1996                 exId = StrTableEscapeQuotedString(exId, strlen(exId), 0);
1997                 dassert(StrTableLen(exId) == 1);
1998                 ReplaceStrTable(&exp->ex_Id, exId);
1999                 break;
2000         case TOK_INTEGER:
2001                 couldconst = 1;
2002                 {
2003                         char *ptr;
2004                         int size = 4;
2005
2006                         strtol(exp->ex_Id, &ptr, 0);
2007                         while (*ptr) {
2008                                 switch(*ptr) {
2009                                 case 'u':
2010                                 case 'U':
2011                                         size |= 0x1000;
2012                                         break;
2013                                 case 's':
2014                                 case 'S':
2015                                         size &= ~0xFFF;
2016                                         break;
2017                                 case 'b':
2018                                 case 'B':
2019                                         size = (size & ~0xFFF) | 1;
2020                                         break;
2021                                 case 'w':
2022                                 case 'W':
2023                                         size = (size & ~0xFFF) | 2;
2024                                         break;
2025                                 case 'i':
2026                                 case 'I':
2027                                         size = (size & ~0xFFF) | 4;
2028                                         break;
2029                                 case 'l':
2030                                 case 'L':
2031                                         size = (size & ~0xFFF) | 8;
2032                                         break;
2033                                 case 'x':
2034                                 case 'X':
2035                                         size = (size & ~0xFFF) | 16;
2036                                         break;
2037                                 case 'z':
2038                                 case 'Z':
2039                                         size = (size & ~0xFFF) |
2040                                         sizeof(runesize_t);
2041                                         break;
2042                                 default:
2043                                         ExpFatalError(exp,
2044                                                       TOK_ERR_ILLEGAL_SUFFIX);
2045                                         /* NOT REACHED */
2046                                         break;
2047                                 }
2048                                 ++ptr;
2049                         }
2050                         switch(size) {
2051                         case 1:
2052                                 exType = &Int8Type;
2053                                 break;
2054                         case 2:
2055                                 exType = &Int16Type;
2056                                 break;
2057                         case 4:
2058                                 exType = &Int32Type;
2059                                 break;
2060                         case 8:
2061                                 exType = &Int64Type;
2062                                 break;
2063                         case 16:
2064                                 exType = &Int128Type;
2065                                 break;
2066                         case 0x1000 | 1:
2067                                 exType = &UInt8Type;
2068                                 break;
2069                         case 0x1000 | 2:
2070                                 exType = &UInt16Type;
2071                                 break;
2072                         case 0x1000 | 4:
2073                                 exType = &UInt32Type;
2074                                 break;
2075                         case 0x1000 | 8:
2076                                 exType = &UInt64Type;
2077                                 break;
2078                         case 0x1000 | 16:
2079                                 exType = &UInt128Type;
2080                                 break;
2081                         default:
2082                                 exType = &Int32Type;
2083                                 break;
2084                         }
2085                 }
2086                 exFlags |= EXF_CONST;
2087                 break;
2088         case TOK_FLOAT:
2089                 couldconst = 1;
2090                 {
2091                         char *ptr;
2092
2093                         exType = &Float64Type;
2094
2095                         strtod(exp->ex_Id, &ptr);
2096                         while (*ptr) {
2097                                 switch(*ptr) {
2098                                 case 'f':
2099                                 case 'F':
2100                                         exType = &Float32Type;
2101                                         break;
2102                                 case 'd':
2103                                 case 'D':
2104                                         exType = &Float64Type;
2105                                         break;
2106                                 case 'x':
2107                                 case 'X':
2108                                         exType = &Float128Type;
2109                                         break;
2110                                 }
2111                                 ++ptr;
2112                         }
2113                 }
2114                 exFlags |= EXF_CONST;
2115                 break;
2116         case TOK_VOIDEXP:
2117                 exType = &VoidType;
2118                 break;
2119         case TOK_SELF:
2120                 /*
2121                  * The self identifier represents the current procedure's
2122                  * arguments.  A varargs procedure will actually be called
2123                  * with an extended version of this type, but for resolution
2124                  * purposes we can use this time.
2125                  *
2126                  * This is an LVALUE to support things like self.new() XXX.
2127                  */
2128                 exType = ADD_LVALUE(resolveArgsType(sg, flags));
2129                 break;
2130         case TOK_DOLLAR:
2131                 /*
2132                  * The '$' identifier represents the current procedure's
2133                  * return storage.
2134                  */
2135                 if (sg->sg_Flags & SGF_DIDRESULT)
2136                         ExpFatalError(exp, TOK_ERR_RESULT_SEQUENCING);
2137                 exType = ADD_LVALUE(resolveReturnType(sg, flags));
2138                 break;
2139         case TOK_ID:
2140         case TOK_CLASSID:
2141                 /*
2142                  * Lookup the identifier.  The returned declaration could 
2143                  * represent a class, typedef, module, or storage, but for
2144                  * this case we only allow storage or a constant.  Since
2145                  * we are starting from our own semantic group, visibility
2146                  * is initially ALL (private, library, and public).
2147                  *
2148                  * The identifier might represent something at a higher scoping
2149                  * layer.  For example, a nested procedure accessing a variable
2150                  * in the parent procedure or a method procedure in a class
2151                  * accessing an element of the object.
2152                  *
2153                  * It is also possible for the current execution scoping layer
2154                  * (sg) to have a secondary contextual layer from which global
2155                  * constants can be accessed.  This is typically set when
2156                  * resolving procedure arguments for procedures called through
2157                  * objects or types.  Only type globals can be accesed via
2158                  * this shortcut.
2159                  *
2160                  * This returns an LVALUE if the id represents storage.
2161                  */
2162                 {
2163                         string_t ary[2];
2164                         int eno = TOK_ERR_ID_NOT_FOUND;
2165
2166                         exDecl = NULL;
2167
2168                         /*
2169                          * Special case 'super'. XXX TY_REFTO
2170                          *
2171                          * Make an in-place change to the expression
2172                          * structure.  'super' is actually 'this' with the
2173                          * EXF_SUPER flag set.
2174                          */
2175                         if (exId == String_Super) {
2176                                 exId = String_This;
2177                                 ReplaceStrTable(&exp->ex_Id, exId);
2178                                 exFlags |= EXF_SUPER;
2179                         }
2180                         ary[0] = exp->ex_Id;
2181                         ary[1] = NULL;
2182
2183                         exDecl = FindDeclPath(&exp->ex_LexRef, isg, sg,
2184                                               NULL, ary,
2185                                               FDC_NULL, &exVisibility,
2186                                               -1, &eno);
2187                         if (exDecl == NULL) {
2188                                 exDecl = FindDeclPathAltContext(
2189                                                       &exp->ex_LexRef, isg, sg,
2190                                                       NULL, ary,
2191                                                       FDC_NULL, &exVisibility,
2192                                                       -1, &eno);
2193                         }
2194                         if (exDecl == NULL) {
2195                                 ExpPrintError(exp, eno);
2196                                 dassert_exp(exp, 0);
2197                         }
2198
2199                         /*
2200                          * The EXF flag is set by TOK_ADDR, possibly
2201                          * propagated down via TOK_DOT.  Use this to flag
2202                          * that the stack context might be used outside of
2203                          * its normal life.  LValue scoped declarations do
2204                          * not count because they have their own RefStor.
2205                          *
2206                          * (This code is primarily responsible for causing
2207                          * SRSGET and SRSPUT instructions to be emitted).
2208                          */
2209                         if ((exFlags & EXF_ADDRUSED) &&
2210                             (exDecl->d_Scope.s_Flags & SCOPE_LVALUE) == 0) {
2211                                 exDecl->d_MyGroup->sg_Flags |= SGF_ADDRUSED;
2212                         }
2213
2214 #if 0
2215                         /*
2216                          * Try to delay resolving the procedure declaration
2217                          * (which will resolve the procedure body).  We cannot
2218                          * delay the resolution if resolving a constant
2219                          * that the resolver needs immediately.
2220                          */
2221                         if (flags & RESOLVE_CONSTEXP) {
2222                                 resolveDecl(exDecl, flags);
2223                         }
2224 #endif
2225                 }
2226
2227                 /*
2228                  * Taking the address of content-locked storage is illegal.
2229                  *
2230                  * If we are running through an LValueStor
2231                  * UNLOCKED applies to it and not its contents.
2232                  * Check to see if the contents are acceptable.
2233                  */
2234                 if ((exFlags & EXF_REQ_ADDROF) &&
2235                    (exDecl->d_Scope.s_Flags & SCOPE_UNLOCKED) == 0) {
2236                         Type *type = exDecl->d_StorDecl.ed_Type;
2237                         if ((type->ty_Flags & TF_HASLVPTR) && 
2238                             type->ty_Op != TY_CLASS &&
2239                             type->ty_Op != TY_ARYOF) {
2240                                 ExpPrintError(exp,
2241                                             TOK_ERR_ILLEGAL_ADDRLOCKED);
2242                                 dassert_exp(exp, 0);
2243                         }
2244                 }
2245
2246                 switch(exDecl->d_Op) {
2247                 case DOP_ARGS_STORAGE:
2248                         if (sg->sg_Flags & SGF_DIDRESULT)
2249                                 ExpFatalError(exp, TOK_ERR_RESULT_SEQUENCING);
2250                         /* fall through */
2251                 case DOP_STACK_STORAGE:
2252                 case DOP_GLOBAL_STORAGE:
2253                 case DOP_GROUP_STORAGE:
2254                         /*
2255                          * Storage identifiers are lvalues.
2256                          *
2257                          * Try to delay this step, giving the language more
2258                          * flexibility in avoiding resolver loops from
2259                          * interdependencies that can cause it to fail.
2260                          *
2261                          * We can't delay this step when resolving an
2262                          * expression that the resolver needs an actual
2263                          * constant result for.
2264                          */
2265                         exType = ADD_LVALUE(exDecl->d_StorDecl.ed_Type);
2266                         if (exDecl->d_Op == DOP_STACK_STORAGE &&
2267                             (exFlags & EXF_ADDRUSED)) {
2268                                 exDecl->d_Flags |= DF_ADDRUSED;
2269                         }
2270                         if (exType->ty_SQFlags & SF_CONST)
2271                                 couldconst = 1;
2272 #if 0
2273                         if (flags & RESOLVE_CONSTEXP) {
2274                                 Exp **asexpp = &exDecl->d_StorDecl.ed_AssExp;
2275                                 if (*asexpp) {
2276                                         *asexpp = DupExp(sg, *asexpp);
2277                                         *asexpp = resolveExp(isg, sg, *asexpp,
2278                                                              DEL_LVALUE(exType),
2279                                                      flags | RESOLVE_AUTOCAST);
2280                                         *asexpp = SetDupExp(sg, *asexpp);
2281                                 }
2282                         }
2283 #endif
2284                         break;
2285                 case DOP_ALIAS:
2286                         /*
2287                          * Aliases are rvalues (even if they could be lvalues).
2288                          */
2289                         exType = DEL_LVALUE(exDecl->d_AliasDecl.ed_Type);
2290                         exFlags |= EXF_ALIAS | EXF_UNARY;
2291
2292                         /*
2293                          * NOTE: exLhs must be NULL if exp is unresolved.
2294                          *       exp tree duplications do not duplicate
2295                          *       the alias's exLHS even though UNARY is set.
2296                          */
2297                         dassert_exp(exp, exLhs == NULL);
2298                         exLhs = DupExp(sg, exDecl->d_AliasDecl.ed_AssExp);
2299                         exLhs = resolveExp(isg, sg, exLhs, exType,
2300                                            flags | RESOLVE_AUTOCAST);
2301
2302                         /*
2303                          * Inherit EXF_NULL (NULL pointer special) through
2304                          * the alias, otherwise it will not be assignable
2305                          * to arbitrary pointers.
2306                          */
2307                         exFlags |= exLhs->ex_Flags & EXF_NULL;
2308                         break;
2309
2310                 case DOP_PROC:
2311                         /*
2312                          * A procedural identifier.
2313                          *
2314                          * Note: procedural pointers cannot be changed so
2315                          *       they are not lvalues.
2316                          */
2317                         dassert_exp(exp, (exFlags & EXF_REQ_PROC));
2318                         exType = exDecl->d_ProcDecl.ed_Type;
2319                         if (exDecl->d_ScopeFlags & SCOPE_PURE)
2320                                 couldconst = 1;
2321                         break;
2322                 case DOP_TYPEDEF:
2323                         if (exFlags & EXF_REQ_TYPE) {
2324                                 exType = exDecl->d_TypedefDecl.ed_Type;
2325                                 exFlags |= EXF_RET_TYPE;
2326                                 break;
2327                         }
2328                         dassert_exp(exp, 0);
2329                         break;
2330                 case DOP_CLASS:
2331                         if (exFlags & EXF_REQ_TYPE) {
2332                                 exType =
2333                     AllocClassType(
2334                             &exDecl->d_ClassDecl.ed_SemGroup->sg_ClassList,
2335                             exDecl->d_ClassDecl.ed_Super,
2336                             exDecl->d_ClassDecl.ed_SemGroup,
2337                             exVisibility);
2338                                 exFlags |= EXF_RET_TYPE;
2339                                 break;
2340                         }
2341                         dassert_exp(exp, 0);
2342                         break;
2343                 case DOP_IMPORT:
2344                         if (exFlags & EXF_REQ_TYPE) {
2345                                 exType =
2346                     AllocImportType(
2347                             &exDecl->d_ImportDecl.ed_SemGroup->sg_ClassList,
2348                             exDecl->d_ImportDecl.ed_SemGroup,
2349                             exVisibility);
2350                                 exFlags |= EXF_RET_TYPE;
2351                                 break;
2352                         }
2353                         dassert_exp(exp, 0);
2354                         break;
2355                 default:
2356                         dassert_exp(exp, 0);
2357                 }
2358                 break;
2359         case TOK_NOT:
2360                 /*
2361                  * NOTE: BoolType global implies an rvalue.
2362                  */
2363                 couldconst = 1;
2364                 exLhs = resolveExp(isg, sg, exLhs, &BoolType,
2365                                    flags | RESOLVE_AUTOCAST);
2366                 break;
2367         case TOK_TYPE:
2368                 if (exFlags & EXF_REQ_TYPE) {
2369                         exType = RESOLVETYPE(exType);
2370                         exFlags |= EXF_RET_TYPE;
2371                 } else {
2372                         dassert_exp(exp, 0);
2373                 }
2374                 break;
2375         case TOK_CAST:
2376                 /*
2377                  * User cast (or maybe the parser inserted it).  Try to
2378                  * resolve the expression with the requested type hint
2379                  * but tell resolveExp() not to force the cast.
2380                  *
2381                  * Then check the result.  If resolveExp() was not able to
2382                  * optimize the requested cast then resolve the cast.
2383                  *
2384                  * If the types are compatible we still keep the TOK_CAST
2385                  * node in place for the moment.  XXX we really need to
2386                  * formalized how ex_Type is set Similar vs Exact.
2387                  *
2388                  * NOTE: Cast results are always an RVALUE.  XXX validate here.
2389                  */
2390                 couldconst = 1;
2391                 if ((exFlags & EXF_PARSE_TYPE) == 0) {
2392                         exRhs->ex_Flags |= EXF_REQ_TYPE;
2393                         exRhs = resolveExp(isg, sg, exRhs, NULL,
2394                                            flags & ~RESOLVE_AUTOCAST);
2395                         exType = exRhs->ex_Type;
2396                 }
2397                 exLhs = resolveExp(isg, sg, exLhs, exType,
2398                                    flags & ~RESOLVE_AUTOCAST);
2399                 if (SimilarType(exType, exLhs->ex_Type) == 0) {
2400                         saveExpCopy(&copy, exp);
2401                         exp = resolveExpCast(isg, sg, exLhs, exType, flags);
2402                         loadExpCopy(&copy, exp);
2403                 }
2404 #if 0
2405                 /* propagate NULL flag to allow cast to any pointer type */
2406                 if (exLhs->ex_Flags & EXF_NULL)
2407                         printf("LHS NULL\n");
2408                 exp->ex_Flags |= exLhs->ex_Flags & EXF_NULL;
2409 #endif
2410                 break;
2411         case TOK_CALL:
2412                 /*
2413                  * Calls require the RHS to be a compound expression
2414                  * representing the procedure arguments.
2415                  *
2416                  * XXX deal with pointer-to-function verses function
2417                  * XXX the lhs must at the moment resolve to the procedure
2418                  * itself.
2419                  *
2420                  * In regards to procedure pointers, the declaration
2421                  * will require a pointer to the procedure's statement
2422                  * body.  XXX this pointer can be the physical storage
2423                  * associated with the lhs data but thus requires the
2424                  * type to be a pointer.  We do not support the 'C'
2425                  * (*ptr_to_func)(...) form.  You have to use ptr_to_func(...).
2426                  */
2427                 {
2428                         Type *ltype;
2429                         Type *atype;            /* type for alt context */
2430                         SemGroup *save_asg;     /* save old alt context */
2431
2432                         dassert_exp(exRhs, exRhs->ex_Token == TOK_COMPOUND);
2433
2434                         /*
2435                          * Note: ex_Flags hints must 'always happen' since
2436                          * we may be modifying an expression that will later
2437                          * be Dup'd.
2438                          */
2439                         exLhs->ex_Flags |= EXF_REQ_PROC;
2440                         exLhs->ex_Flags |= EXF_ADDRUSED;
2441                         exLhs = resolveExp(isg, sg, exLhs, NULL,
2442                                            flags & ~RESOLVE_AUTOCAST);
2443                         ltype = exLhs->ex_Type;
2444 #if 0
2445                         if (ltype->ty_Op == TY_PTRTO)
2446                                 ltype = type->ty_PtrType.et_Type; /* XXX */
2447 #endif
2448 #if 0
2449                         dassert_exp(exLhs, exLhs->ex_Token == TOK_DECL ||
2450                                            exLhs->ex_Token == TOK_ID);
2451 #endif
2452                         dassert_exp(exLhs, ltype != NULL &&
2453                                            ltype->ty_Op == TY_PROC);
2454                         dassert_exp(exLhs, exLhs->ex_Decl != NULL);
2455                         dassert_exp(exRhs, exRhs->ex_Token == TOK_COMPOUND);
2456
2457                         /*
2458                          * If the lhs type indicates a method procedure, then
2459                          * it's lhs is the object we wish to pass as the
2460                          * first argument to the method.  We move the lhs lhs
2461                          * exp.  For a STRIND TY_PTRTO method call we
2462                          * indirect the element and convert it to a TOK_DOT
2463                          * lvalue argument of the underlying object.
2464                          *
2465                          * A method call via a reference object is a very
2466                          * weird case.
2467                          *
2468                          * Since the method called through an object winds up
2469                          * being a method taylored for that object, and we
2470                          * are calling through a reference to an object,
2471                          * the actual method will be looked up at run time
2472                          * and will match the object.  Thus we can safely
2473                          * indirect through the reference object for this
2474                          * one case.  Since (*ref_obj) is not normally
2475                          * allowed this will be special-cased at
2476                          * compile/run-time.
2477                          *
2478                          * Note that this occurs before we evaluate the
2479                          * compound expression on the right hand side.  Also
2480                          * note that since the resolver can be called multiple
2481                          * times on a shared expression, we have to be
2482                          * careful to shift the arguments around only once.
2483                          */
2484                         if ((ltype->ty_SQFlags & SF_METHOD) && 
2485                             (exRhs->ex_Flags & EXF_CALL_CONV) == 0
2486                         ) {
2487                                 Exp *obj;
2488
2489                                 exRhs->ex_Flags |= EXF_CALL_CONV;
2490
2491                                 switch(exLhs->ex_Token) {
2492                                 case TOK_STRIND:        /* indirect */
2493                                         /*
2494                                          * NOTE: Do not set EXF_RESOLVED, we
2495                                          *       need to call the resolver to
2496                                          *       properly propagate ADDRUSED.
2497                                          */
2498                                         obj = exLhs->ex_Lhs;
2499                                         if (methodProcThisIsPointer(ltype)) {
2500                                                 ;
2501                                         } else if (obj->ex_Type->ty_Op ==
2502                                                    TY_PTRTO) {
2503                                                 Exp *nexp = AllocExp(NULL);
2504
2505                                                 nexp->ex_Lhs = obj;
2506                                                 nexp->ex_Token = TOK_PTRIND;
2507                                                 nexp->ex_Type = ADD_LVALUE(obj->ex_Type->ty_PtrType.et_Type);
2508                                                 nexp->ex_Flags |= EXF_UNARY;
2509                                                 LexDupRef(&obj->ex_LexRef,
2510                                                           &nexp->ex_LexRef);
2511                                                 exLhs->ex_Token = TOK_DOT;
2512                                                 obj = nexp;
2513                                         } else if (obj->ex_Type->ty_Op ==
2514                                                    TY_CPTRTO) {
2515                                                 Exp *nexp = AllocExp(NULL);
2516
2517                                                 nexp->ex_Lhs = obj;
2518                                                 nexp->ex_Token = TOK_PTRIND;
2519                                                 nexp->ex_Type = ADD_LVALUE(obj->ex_Type->ty_CPtrType.et_Type);
2520                                                 nexp->ex_Flags |= EXF_UNARY;
2521                                                 LexDupRef(&obj->ex_LexRef,
2522                                                           &nexp->ex_LexRef);
2523                                                 exLhs->ex_Token = TOK_DOT;
2524                                                 obj = nexp;
2525                                         } else if (obj->ex_Type->ty_Op ==
2526                                                     TY_REFTO) {
2527                                                 Exp *nexp = AllocExp(NULL);
2528
2529                                                 nexp->ex_Lhs = obj;
2530                                                 nexp->ex_Token = TOK_PTRIND;
2531                                                 nexp->ex_Type = ADD_LVALUE(obj->ex_Type->ty_RefType.et_Type);
2532                                                 nexp->ex_Flags |= EXF_UNARY |
2533                                                                   EXF_INDREF;
2534                                                 LexDupRef(&obj->ex_LexRef,
2535                                                           &nexp->ex_LexRef);
2536                                                 obj = nexp;
2537                                         } else {
2538                                                 dassert_exp(obj, 0);
2539                                         }
2540                                         break;
2541                                 case TOK_DOT:
2542                                         /*
2543                                          * Pass directly as an lvalue.  If this
2544                                          * is a pointer or reference only the
2545                                          * builtin methods for the Pointer
2546                                          * class are possible.  These methods
2547                                          * require a content-locked pointer.
2548                                          */
2549                                         obj = exLhs->ex_Lhs;
2550                                         if (obj->ex_Type->ty_Op != TY_PTRTO &&
2551                                             obj->ex_Type->ty_Op != TY_REFTO) {
2552                                                 break;
2553                                         }
2554
2555                                         if (obj->ex_Decl == NULL ||
2556                                             (obj->ex_Decl->d_Scope.s_Flags &
2557                                              SCOPE_UNLOCKED)) {
2558                                                 exFlags |= EXF_UNLOCKEDMTH;
2559                                         }
2560                                         break;
2561                                 default:
2562                                         dassert_exp(exp, 0);
2563                                         obj = NULL;
2564                                         break;
2565                                 }
2566
2567                                 /*
2568                                  * Leave the lhs intact, but set the
2569                                  * duplication flag in case things get
2570                                  * nasty later.
2571                                  */
2572                                 exLhs->ex_Lhs = SetDupExp(sg, exLhs->ex_Lhs);
2573                                 obj->ex_Next = exRhs->ex_Lhs;
2574                                 exRhs->ex_Lhs = obj;
2575
2576                                 atype = obj->ex_Type;
2577                         } else {
2578                                 atype = NULL;
2579                         }
2580
2581                         /*
2582                          * Try to set an alternative search context during
2583                          * resolution of the procedure arguments.  This context
2584                          * is only searched if an identifier cannot be found
2585                          * through normal means so local variables and such
2586                          * will override it as the programmer should expect.
2587                          * Since the local semantic stack is under the
2588                          * programmer's control, unexpected collisions should
2589                          * either not occur or be easily fixed.
2590                          */
2591                         if (atype) {
2592                                 switch(atype->ty_Op) {
2593                                 case TY_REFTO:
2594                                         atype = atype->ty_PtrType.et_Type;
2595                                         break;
2596                                 case TY_PTRTO:
2597                                         atype = atype->ty_PtrType.et_Type;
2598                                         break;
2599                                 }
2600                                 if (atype->ty_Op != TY_CLASS)
2601                                         atype = NULL;
2602                         }
2603                         if (atype) {
2604                                 save_asg = sg->sg_AltContext;
2605                                 sg->sg_AltContext = atype->ty_ClassType.et_SemGroup;
2606                         } else {
2607                                 save_asg = NULL;
2608                         }
2609
2610                         /*
2611                          * Resolve the right hand side, which are the
2612                          * procedure arguments as a compound type.  This
2613                          * can get tricky.  XXX
2614                          *
2615                          * NOTE: We inherit the SF_LVALUE flag from the
2616                          *       return type.  Parent might turn it off.
2617                          */
2618                         /*d = exLhs->ex_Decl;*/
2619                         exRhs = resolveExp(isg, sg, exRhs,
2620                                            ltype->ty_ProcType.et_ArgsType,
2621                                            flags | RESOLVE_AUTOCAST);
2622                         exType = ltype->ty_ProcType.et_RetType;
2623                         if (atype) {
2624                                 /*
2625                                  * Restore AltContext after resolving rhs.
2626                                  */
2627                                 sg->sg_AltContext = save_asg;
2628                         } else if ((exRhs->ex_Flags & (EXF_CONST |
2629                                                        EXF_PROBCONST)) &&
2630                                    (exLhs->ex_Decl->d_ScopeFlags & SCOPE_PURE)) {
2631                                 /*
2632                                  * atype NULL (not method call, which requires
2633                                  * an object), arguments can become constants,
2634                                  * pure function, so result can become a
2635                                  * constant.
2636                                  */
2637                                 exFlags |= EXF_PROBCONST;
2638                         }
2639                 }
2640                 break;
2641         case TOK_COMPOUND:
2642                 /*
2643                  * (NOTE EARLY RETURN)
2644                  *
2645                  * A compound expression should always be an RVALUE, but
2646                  * might contain LVALUEs (XXX).
2647                  */
2648                 couldconst = 1;
2649                 exp = resolveCompoundExp(isg, sg, exp, itype, flags);
2650                 return(exp);
2651                 /* not reached */
2652         case TOK_TYPEOF:
2653                 /*
2654                  * The caller must be able to handle a type return when
2655                  * typeof() is used.
2656                  */
2657                 dassert_exp(exp, exFlags & EXF_REQ_TYPE);
2658                 /* fall through */
2659         case TOK_SIZEOF:
2660         case TOK_ARYSIZE:
2661                 /*
2662                  * If an expression was supplied, convert it to a type.
2663                  *
2664                  * NOTE: ex_Flags hints must 'always happen' since we may be
2665                  *       modifying an expression that will later be Dup'd.
2666                  */
2667                 couldconst = 1;
2668                 if ((exFlags & EXF_RET_TYPE) == 0) {
2669                         dassert(exLhs != NULL);
2670                         exLhs->ex_Flags |= EXF_REQ_TYPE;
2671                         exLhs = resolveExp(isg, sg, exLhs, NULL,
2672                                            flags & ~RESOLVE_AUTOCAST);
2673                         exType = exLhs->ex_Type;
2674 #if 1
2675                         /* do not clear EXF_UNARY, messes up tmp exp storage */
2676                         /* exFlags &= ~EXF_UNARY; */
2677 #endif
2678                         exFlags |= EXF_RET_TYPE;
2679                         /* XXX delete the lhs */
2680                 } else {
2681                         exType = RESOLVETYPE(exType);
2682                 }
2683                 switch(exToken) {
2684                 case TOK_SIZEOF:
2685                         exId = StrTableInt(exType->ty_Bytes);
2686                         exp->ex_Token = exToken = TOK_INTEGER;
2687                         exType = &SizeType;
2688                         exFlags &= ~EXF_RET_TYPE;
2689                         exFlags |= EXF_CONST;
2690                         break;
2691                 case TOK_ARYSIZE:
2692                         dassert_exp(exp, exType->ty_Op == TY_ARYOF);
2693                         if (exType->ty_AryType.et_Type->ty_Bytes) {
2694                                 exId = StrTableInt(exType->ty_Bytes /
2695                                         exType->ty_AryType.et_Type->ty_Bytes);
2696                         } else {
2697                                 exId = StrTableInt(0);
2698                         }
2699                         exp->ex_Token = exToken = TOK_INTEGER;
2700                         exType = &SizeType;
2701                         exFlags &= ~EXF_RET_TYPE;
2702                         exFlags |= EXF_CONST;
2703                         /* exLhs = NULL; */
2704                         break;
2705                 case TOK_TYPEOF:
2706                         /* type is returned */
2707                         break;
2708                 }
2709                 break;
2710         default:
2711                 dassert_exp(exp, 0);
2712                 break;
2713         }
2714
2715         /*
2716          * Resolve the type and cast-to-type.
2717          */
2718         if (exType) {
2719                 exType = RESOLVETYPE(exType);
2720                 /* XXX exType was ex_Type */
2721
2722                 /*
2723                  * Special-case compound compatibility issues so the
2724                  * interpreter and code generator do not have to deal with
2725                  * it.
2726                  */
2727                 if ((flags & RESOLVE_AUTOCAST) && itype && 
2728                     itype->ty_Op == TY_COMPOUND &&
2729                     exType->ty_Op != TY_COMPOUND) {
2730                         /*
2731                          * The expression parser might have optimized-out
2732                          * the TOK_COMPOUND wrapper around single-element
2733                          * parenthesized expressions.  Add it back in if
2734                          * the cast target expects a compound expression.
2735                          *
2736                          * XXX Currently hack a SetDupExp() to avoid
2737                          *     re-resolving the already-resolved component.
2738                          */
2739                         SetDupExp(sg, exp);
2740                         saveExpCopy(&copy, exp);
2741                         exp = ExpToCompoundExp(exp, TOK_COMPOUND);
2742                         exp = resolveCompoundExp(isg, sg, exp, itype, flags);
2743                         loadExpCopy(&copy, exp);
2744                 } else
2745                 if ((flags & RESOLVE_AUTOCAST) && itype && 
2746                     itype->ty_Op == TY_CLASS &&
2747                     exType->ty_Op == TY_CLASS &&
2748                     itype != &VoidType &&
2749                     (itype->ty_Flags & (TF_ISBOOL | TF_ISINTEGER |
2750                                         TF_ISFLOATING)) == 0 &&
2751                     (exType->ty_Flags & (TF_ISBOOL | TF_ISINTEGER |
2752                                          TF_ISFLOATING))) {
2753                         /*
2754                          * The expression parser might have optimized-out
2755                          * the TOK_COMPOUND wrapper around single-element
2756                          * parenthesized expressions used in a class iterator
2757                          * (in an assignment).  Add it back in if the
2758                          * itype is a non-core class and exType is a core
2759                          * class.
2760                          *
2761                          * XXX Currently hack a SetDupExp() to avoid
2762                          *     re-resolving the already-resolved component.
2763                          */
2764                         SetDupExp(sg, exp);
2765                         saveExpCopy(&copy, exp);
2766                         exp = ExpToCompoundExp(exp, TOK_COMPOUND);
2767                         exp = resolveCompoundExp(isg, sg, exp, itype, flags);
2768                         loadExpCopy(&copy, exp);
2769                 }
2770
2771                 /*
2772                  * If the type hint did not succeed we may have to cast the
2773                  * expression to the requested type.  Note that if the itype
2774                  * was set as part of an array optimization request which could
2775                  * not be handled, we must ignore itype.
2776                  *
2777                  * Note that SimilarType() will allow exp->ex_Type to be a
2778                  * var-args TY_ARGS, and since the original Rhs of a call
2779                  * is set to the procedure arguments type, VarType.et_Type
2780                  * should match exactly.
2781                  */
2782                 if (itype &&
2783                     (exFlags & (EXF_REQ_ARRAY|EXF_RET_ARRAY)) != EXF_REQ_ARRAY
2784                 ) {
2785                         if ((itype->ty_Flags & TF_RESOLVED) == 0)
2786                                 itype = RESOLVETYPE(itype);
2787                         if ((itype->ty_SQFlags & SF_LVALUE) &&
2788                             (exType->ty_SQFlags & SF_LVALUE) == 0
2789                         ) {
2790                                 /* XXX */
2791                                 fprintf(stderr, "Exp must be an lvalue here\n");
2792                                 dassert_exp(exp, 0);
2793                         }
2794
2795                         if (!SimilarType(itype, exType) &&
2796                             (flags & RESOLVE_AUTOCAST)) {
2797                                 if (exp->ex_Flags & EXF_DUPEXP) {
2798                                         Exp *nexp = AllocExp(NULL);
2799
2800                                         nexp->u = exp->u;
2801                                         LexDupRef(&exp->ex_LexRef,
2802                                                   &nexp->ex_LexRef);
2803                                         exp = nexp;
2804                                         exFlags &= ~EXF_DUPEXP;
2805                                         /*exp = DupExp(sg, exp);*/
2806                                 }
2807                                 exFlags |= EXF_RESOLVED;
2808                                 exp = dupExpCopy(&copy, exp);
2809                                 exp = resolveExpCast(isg, sg, exp, itype,
2810                                                      flags);
2811                                 loadExpCopy(&copy, exp);
2812                         }
2813                 }
2814         }
2815
2816         /*
2817          * Generic constant evaluation flag.  Note that EXF_PROBCONST
2818          * could also be set above (TOK_CALL).
2819          */
2820         if (couldconst &&
2821             (exLhs == NULL || (exLhs->ex_Flags & (EXF_CONST|EXF_PROBCONST))) &&
2822             (exRhs == NULL || (exRhs->ex_Flags & (EXF_CONST|EXF_PROBCONST)))) {
2823                 exFlags |= EXF_PROBCONST;
2824         }
2825
2826         exFlags |= EXF_RESOLVED;
2827         exp = dupExpCopy(&copy, exp);
2828         return(exp);
2829 }
2830
2831 /*
2832  * Resolve an expression for which the resolver needs the result
2833  * immediately.
2834  */
2835 Exp *
2836 resolveConstExp(SemGroup *isg, SemGroup *sg, Exp *exp, int flags)
2837 {
2838         runesize_t tmpbytes;
2839         runesize_t tmpalign;
2840         runesize_t ooffset;
2841         int oflags;
2842
2843         flags &= ~RESOLVE_AUTOCAST;
2844
2845         if ((exp->ex_Flags & EXF_RESOLVED) == 0)
2846                 exp = resolveExp(isg, sg, exp, NULL, flags);
2847
2848         oflags = exp->ex_Flags;
2849         ooffset = exp->ex_TmpOffset;
2850         tmpbytes = 0;
2851         tmpalign = 0;
2852         resolveStorageExpAlign(exp, &tmpalign, RESOLVE_CONSTEXP);
2853         resolveStorageExp(exp, &tmpbytes);
2854
2855         if ((exp->ex_Flags & (EXF_CONST | EXF_PROBCONST)) == 0) {
2856                 ExpPrintError(exp, TOK_ERR_EXPECTED_INTEGRER_CONST);
2857                 dassert_exp(exp, 0);
2858         }
2859
2860         /*
2861          * Special interpreter execution to resolve the expression.
2862          */
2863         {
2864                 RunContext ct;
2865                 rundata_t data;
2866                 union {
2867                         int64_t tmpbuf[128];
2868                         float128_t tmpflt[64];
2869                 } u;
2870
2871                 bzero(&ct, sizeof(ct));
2872                 ct.ct_Flags |= CTF_RESOLVING;
2873                 if (sg->sg_TmpBytes < (runesize_t)sizeof(u.tmpbuf) &&
2874                     sg->sg_TmpAlignMask < (runesize_t)sizeof(float128_t))
2875                         ct.ct_TmpData = (char *)u.tmpbuf;
2876                 else
2877                         posix_memalign((void *)&ct.ct_TmpData,
2878                                        sg->sg_TmpAlignMask + 1,
2879                                        sg->sg_TmpBytes);
2880
2881                 ct.ct_TmpBytes = sg->sg_TmpBytes;
2882                 ct.ct_CtxRefStor.rs_Refs = 1;
2883                 exp->ex_Run(&ct, &data, exp);
2884
2885                 if ((exp->ex_Flags & EXF_CONST) == 0) {
2886                         ExpPrintError(exp, TOK_ERR_EXPECTED_INTEGRER_CONST);
2887                         dassert_exp(exp, 0);
2888                 }
2889                 if (ct.ct_TmpData != (char *)u.tmpbuf)
2890                         free(ct.ct_TmpData);
2891         }
2892
2893         /*
2894          * exp is now a constant, restore the original ex_TmpOffset
2895          * for normal execution/operation (the storage may be needed for
2896          * large constants).
2897          */
2898         if (oflags & EXF_TMPRESOLVED) {
2899                 exp->ex_TmpOffset = ooffset;
2900                 resolveStorageExp(exp, &tmpbytes);
2901         } else {
2902                 exp->ex_TmpOffset = -1;
2903                 exp->ex_Flags &= ~EXF_TMPRESOLVED;
2904         }
2905
2906         return exp;
2907 }
2908
2909 Exp *
2910 resolveConstExpBool(SemGroup *isg, SemGroup *sg, Exp *exp, int flags,
2911                     RunTmpStor *ts)
2912 {
2913         runesize_t tmpbytes;
2914         runesize_t tmpalign;
2915         runesize_t ooffset;
2916         int oflags;
2917
2918         flags &= ~RESOLVE_AUTOCAST;
2919
2920         if ((exp->ex_Flags & EXF_RESOLVED) == 0) {
2921                 exp = resolveExp(isg, sg, exp, NULL, flags);
2922         }
2923
2924         /*
2925          * [re]-resolve the storage from 0 so we can execute the expression.
2926          */
2927         oflags = exp->ex_Flags;
2928         ooffset = exp->ex_TmpOffset;
2929         tmpbytes = 0;
2930         tmpalign = 0;
2931         resolveStorageExpAlign(exp, &tmpalign, RESOLVE_CONSTEXP);
2932         resolveStorageExp(exp, &tmpbytes);
2933         if ((exp->ex_Flags & (EXF_CONST | EXF_PROBCONST)) == 0) {
2934                 ExpPrintError(exp, TOK_ERR_EXPECTED_INTEGRER_CONST);
2935                 dassert_exp(exp, 0);
2936         }
2937
2938         /*
2939          * Special interpreter execution to resolve the expression.
2940          */
2941         {
2942                 RunContext ct;
2943                 RunTmpStor *rts;
2944                 rundata_t data;
2945                 union {
2946                         int64_t tmpbuf[128];
2947                         float128_t tmpflt[64];
2948                 } u;
2949
2950                 bzero(&ct, sizeof(ct));
2951                 ct.ct_Flags |= CTF_RESOLVING;
2952
2953                 /*
2954                  * XXX
2955                  */
2956                 if (tmpbytes < (runesize_t)sizeof(u.tmpbuf))
2957                         ct.ct_TmpData = (char *)u.tmpbuf;
2958                 else
2959                         posix_memalign((void *)&ct.ct_TmpData, 16, tmpbytes);
2960                 ct.ct_TmpBytes = tmpbytes;
2961                 ct.ct_CtxRefStor.rs_Refs = 1;
2962                 exp->ex_Run(&ct, &data, exp);
2963                 rts = data.data;
2964
2965                 if ((exp->ex_Flags & EXF_CONST) == 0) {
2966                         ExpPrintError(exp, TOK_ERR_EXPECTED_INTEGRER_CONST);
2967                         dassert_exp(exp, 0);
2968                 }
2969                 ts->ts_Bool = rts->ts_Bool;
2970                 if (ct.ct_TmpData != (char *)u.tmpbuf)
2971                         free(ct.ct_TmpData);
2972         }
2973
2974         /*
2975          * exp is now a constant, restore the original ex_TmpOffset
2976          * for normal execution/operation (the storage may be needed for
2977          * large constants).
2978          */
2979         if (oflags & EXF_TMPRESOLVED) {
2980                 exp->ex_TmpOffset = ooffset;
2981                 resolveStorageExp(exp, &tmpbytes);
2982         } else {
2983                 exp->ex_TmpOffset = -1;
2984                 exp->ex_Flags &= ~EXF_TMPRESOLVED;
2985         }
2986
2987         return exp;
2988 }
2989
2990 /*
2991  * Extract constant from already-constant-resolved expression.
2992  * resolveConstExp() must have previously been called on exp.
2993  *
2994  * Expression must have already been constant-optimized, meaning
2995  * that we should be able to execute it without a context to access
2996  * the cached results in exp->u.
2997  */
2998 static
2999 int64_t
3000 resolveGetConstExpInt64(Exp *exp)
3001 {
3002         rundata_t data;
3003         int64_t value;
3004
3005         dassert_exp(exp, exp->ex_Token == TOK_INTEGER ||
3006                          (exp->ex_Flags & EXF_CONST));
3007         exp->ex_Run(NULL, &data, exp);
3008
3009         if (exp->ex_Type->ty_Flags & TF_ISUNSIGNED) {
3010                 switch(exp->ex_Type->ty_Bytes) {
3011                 case 1:
3012                         value = *(uint8_t *)data.data;
3013                         break;
3014                 case 2:
3015                         value = *(uint16_t *)data.data;
3016                         break;
3017                 case 4:
3018                         value = *(uint32_t *)data.data;
3019                         break;
3020                 case 8:
3021                         value = *(uint64_t *)data.data;
3022                         break;
3023                 default:
3024                         value = 0;
3025                         dassert_exp(exp, 0);
3026                         break;
3027                 }
3028         } else {
3029                 switch(exp->ex_Type->ty_Bytes) {
3030                 case 1:
3031                         value = *(int8_t *)data.data;
3032                         break;
3033                 case 2:
3034                         value = *(int16_t *)data.data;
3035                         break;
3036                 case 4:
3037                         value = *(int32_t *)data.data;
3038                         break;
3039                 case 8:
3040                         value = *(int64_t *)data.data;
3041                         break;
3042                 default:
3043                         value = 0;
3044                         dassert_exp(exp, 0);
3045                         break;
3046                 }
3047         }
3048         return value;
3049 }
3050
3051 static
3052 float128_t
3053 resolveGetConstExpFloat128(Exp *exp)
3054 {
3055         rundata_t data;
3056         float128_t value;
3057
3058         dassert_exp(exp, exp->ex_Token == TOK_FLOAT ||
3059                          (exp->ex_Flags & EXF_CONST));
3060         exp->ex_Run(NULL, &data, exp);
3061
3062         switch(exp->ex_Type->ty_Bytes) {
3063         case 4:
3064                 value = (float128_t)*(float32_t *)data.data;
3065                 break;
3066         case 8:
3067                 value = (float128_t)*(float64_t *)data.data;
3068                 break;
3069         case 16:
3070                 value = *(float128_t *)data.data;
3071                 break;
3072         default:
3073                 value = 0;
3074                 dassert_exp(exp, 0);
3075                 break;
3076         }
3077         return value;
3078 }
3079
3080 /*
3081  * resolveCompoundExp() - resolve a compound expression (called from 
3082  *                        resolveExp() and resolveExpOper()).
3083  *
3084  * Resolve a compound expression.  Compound expressions require
3085  * a compound type to normalize against.  This will work for
3086  * direct assignments, return values, casts, and procedure arguments
3087  * only. 
3088  *
3089  * NOTE: We can't use itype if EXF_REQ_ARRAY is specified because
3090  *       its hinting for the array optimization case, which we cannot do.
3091  *
3092  * Compound expressions may be used in conjuction with types 
3093  * reprsenting classes, compound types, and procedure arguments.  The
3094  * compound expression may contain subclasses of the superclasses expected
3095  * by itype.  This is only allowed if the procedure's body has not yet been
3096  * generated (for example, a method call in a subclass).
3097  *
3098  * Partially resolved operators are typically converted into procedure calls
3099  * and method calls are also partially resolved, so some elements may already 
3100  * be resolved.
3101  *
3102  * XXX named initialization, missing elements (structural
3103  * initialization), and so forth needs to be dealt with.
3104  */
3105 Exp *
3106 resolveCompoundExp(SemGroup *isg, SemGroup *sg, Exp *exp,
3107                    Type *itype, int flags)
3108 {
3109         Exp **pscan;
3110         Exp *scan;
3111         Declaration *d;
3112         SemGroup *sg2;
3113         int varargs = 0;
3114         int isconst = 1;
3115         Type *type;
3116         Type *stype;
3117
3118         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
3119
3120         /*
3121          * Expression dup()ing
3122          */
3123         if (exp->ex_Flags & EXF_DUPEXP) {
3124 #if DUPEXP_DEBUG
3125                 static int count; fprintf(stderr, "DUPEXPC %d\n", ++count);
3126 #endif
3127                 exp = DupExp(sg, exp);
3128         }
3129
3130         if (itype && (exp->ex_Flags & EXF_REQ_ARRAY) == 0)
3131                 exp->ex_Type = itype;
3132
3133         /*
3134          * If we don't have a SemGroup to normalize against, XXX how should
3135          * we normalize the compound expression?
3136          */
3137         if (exp->ex_Type == NULL) {
3138                 dassert_exp(exp, 0);
3139         }
3140
3141         /*
3142          * Normalize the compound expression based on the
3143          * argument types expected by the procedure.  We have
3144          * to resolve the type before we start the scan in order
3145          * to ensure that d_Offset is properly assigned.
3146          *
3147          * Use the declarations found in the compound type 
3148          * semantic group to coerce the procedure arguments to
3149          * generate the correct compound type.  Note that resolveExp()
3150          * recursion must still use the SemGroup that was passed to us.
3151          *
3152          * XXX deal with defaults and pre-resolved arguments. XXX
3153          */
3154         type = exp->ex_Type = RESOLVETYPE(exp->ex_Type);
3155
3156         switch(type->ty_Op) {
3157         case TY_ARGS:
3158                 sg2 = type->ty_ArgsType.et_SemGroup;
3159                 break;
3160         case TY_VAR:
3161                 sg2 = type->ty_VarType.et_SemGroup;
3162                 break;
3163         case TY_COMPOUND:
3164                 sg2 = type->ty_CompType.et_SemGroup;
3165                 break;
3166         case TY_CLASS:
3167                 sg2 = type->ty_ClassType.et_SemGroup;
3168                 break;
3169         default:
3170                 dassert_exp(exp, 0);
3171                 sg2 = NULL;     /* NOT REACHED */
3172                 break;
3173         }
3174         pscan = &exp->ex_Lhs;
3175
3176         /*
3177          * Scan the compound expression and match it up against the compound
3178          * type.
3179          */
3180         d = RUNE_FIRST(&sg2->sg_DeclList);
3181         while ((scan = *pscan) != NULL) {
3182                 if (scan->ex_ArgId != NULL) {
3183                         /*
3184                          * Named argument, find it
3185                          *
3186                          * (Overloading not allowed)
3187                          */
3188                         int eno = TOK_ERR_ID_NOT_FOUND;
3189                         Declaration *nd;
3190
3191                         nd = FindDeclId(sg2, scan->ex_ArgId, &eno);
3192                         if (nd == NULL) {
3193                                 ExpFatalError(scan, eno);
3194                                 /* NOT REACHED */
3195                         }
3196
3197                         /*
3198                          * XXX for now, punt on setting EXF_PROBCONST
3199                          * if the named argument skips a declaration.
3200                          */
3201                         if (nd != d && nd != RUNE_NEXT(d, d_Node)) {
3202                                 isconst = 0;
3203                         }
3204                         d = nd;
3205                 } else {
3206                         /*
3207                          * Unnamed argument, run through sequentially.  Skip
3208                          * any non-storage or global storage.
3209                          */
3210                         while (d && d->d_Op != DOP_ARGS_STORAGE &&
3211                                 d->d_Op != DOP_STACK_STORAGE &&
3212                                 d->d_Op != DOP_GROUP_STORAGE
3213                         ) {
3214                                 d = RUNE_NEXT(d, d_Node);
3215                         }
3216
3217                         /*
3218                          * Ran out of storage declarations.  If this is a
3219                          * var-args SemGroup then we actually create a new
3220                          * SemGroup (and eventually a new type) to represent
3221                          * it.
3222                          *
3223                          * We then extend the varargs SemGroup.  This isn't
3224                          * pretty.
3225                          */
3226                         if (d == NULL) {
3227                                 if (varargs == 0 &&
3228                                     (sg2->sg_Flags & SGF_VARARGS)) {
3229                                         sg2 = DupSemGroup(sg2->sg_Parent, NULL, sg2, 1);
3230 #if 0
3231                                         if (resolveSemGroup1(sg3, flags) &&
3232                                             resolveSemGroup2(sg3, flags))
3233                                                 resolveSemGroup3(sg3, flags);
3234                                         sg2 = sg3;
3235 #endif
3236                                         varargs = 1;
3237                                 }
3238                                 if (varargs == 0) {
3239                                         fprintf(stderr,
3240                                                 "Too many arguments in "
3241                                                 "expression\n");
3242                                         dassert_exp(scan, 0);
3243                                 }
3244                         }
3245                 }
3246
3247                 /*
3248                  * Unlink the expression from the compound list temporarily
3249                  * so we can safely resolve it.  Either cast the expression
3250                  * to the compound element, or create a compound element
3251                  * (e.g. varargs call) to match the expression.
3252                  *
3253                  * Due to the resolver moving things around, the elements of
3254                  * a compound expression are sometimes resolved multiple times.
3255                  */
3256                 *pscan = scan->ex_Next;
3257                 scan->ex_Next = NULL;
3258                 if (d) {
3259                         Type *dtype = d->d_StorDecl.ed_Type;
3260                         int sflags;
3261
3262                         /*
3263                          * HACK! XXX YYY
3264                          */
3265                         if (SimilarType(dtype, &PointerType) &&
3266                             (dtype->ty_SQFlags & SF_LVALUE) == SF_LVALUE
3267                         ) {
3268                                 dtype = NULL;
3269                                 sflags = flags & ~RESOLVE_AUTOCAST;
3270                         } else {
3271                                 sflags = flags | RESOLVE_AUTOCAST;
3272                         }
3273
3274                         /*
3275                          * LValueStor needs a RS, set ADDRUSED to make sure
3276                          * its available to the generator.
3277                          */
3278                         if (d->d_ScopeFlags & SCOPE_LVALUE)
3279                                 scan->ex_Flags |= EXF_ADDRUSED;
3280
3281                         if ((scan->ex_Flags & EXF_RESOLVED) == 0) {
3282                                 scan = resolveExp(isg, sg, scan,
3283                                                   dtype, sflags);
3284                         } else if (dtype) {
3285                                 /*
3286                                  * Since we have already resolved the
3287                                  * expression we need to do the same sanity
3288                                  * checking that it would do to cast.
3289                                  */
3290                                 dassert_exp(scan,
3291                                     (dtype->ty_SQFlags & SF_LVALUE) == 0 ||
3292                                     (scan->ex_Type->ty_SQFlags & SF_LVALUE));
3293                                 if (!SimilarType(dtype, scan->ex_Type)) {
3294                                         scan = resolveExpCast(isg, sg, scan,
3295                                                               dtype, flags);
3296                                 }
3297                         }
3298                 } else {
3299                         Scope tscope = INIT_SCOPE(0);
3300
3301                         if ((scan->ex_Flags & EXF_RESOLVED) == 0)
3302                                 scan = resolveExp(isg, sg, scan, NULL,
3303                                                   flags & ~RESOLVE_AUTOCAST);
3304                         dassert(varargs != 0);
3305                         d = AllocDeclaration(sg2, DOP_ARGS_STORAGE, &tscope);
3306                         d->d_StorDecl.ed_Type = DEL_LVALUE(scan->ex_Type);
3307                         ++sg2->sg_VarCount;
3308                         d->d_Bytes = scan->ex_Type->ty_Bytes;
3309                         d->d_AlignMask = scan->ex_Type->ty_AlignMask;
3310
3311                         /*
3312                          * __align(%d) scope qualifier, override the type's
3313                          * alignment
3314                          */
3315                         if ((d->d_Scope.s_Flags & SCOPE_ALIGN) &&
3316                             d->d_Scope.s_AlignOverride) {
3317                                 d->d_AlignMask = d->d_Scope.s_AlignOverride - 1;
3318                         }
3319
3320 #if 0
3321                         sg2->sg_Bytes = (sg2->sg_Bytes + d->d_AlignMask) &
3322                                         ~d->d_AlignMask;
3323 #endif
3324                         d->d_Offset = sg2->sg_Bytes;
3325                         d->d_Storage = GENSTAT_LOCK;
3326 #if 0
3327                         sg2->sg_Bytes += d->d_Bytes;
3328                         if (sg2->sg_AlignMask < d->d_AlignMask)
3329                                 sg2->sg_AlignMask = d->d_AlignMask;
3330 #endif
3331                 }
3332
3333                 /*
3334                  * Relink and check if constant
3335                  */
3336                 scan->ex_Next = *pscan;
3337                 *pscan = scan;
3338                 if ((scan->ex_Flags & (EXF_CONST | EXF_PROBCONST)) == 0)
3339                         isconst = 0;
3340                 stype = scan->ex_Type;
3341
3342                 /*
3343                  * If the declaration requires an LVALUE, assert that
3344                  * we have an lvalue.  Otherwise set the direct-store
3345                  * request (also see InterpCompoundExp).
3346                  */
3347                 if (d->d_ScopeFlags & SCOPE_LVALUE) {
3348                         if ((stype->ty_SQFlags & SF_LVALUE) == 0)
3349                                 fprintf(stderr, "argument must be an lvalue\n");
3350                         dassert_exp(scan, stype->ty_SQFlags & SF_LVALUE);
3351                 }
3352
3353 #if 1
3354                 /*
3355                  * Check content locking state against scan.  Only matters
3356                  * when passing a pointer as an lvalue since only pointers
3357                  * can be content-locked.
3358                  *
3359                  * We don't have to worry if we are passing a pointer as an
3360                  * rvalue since the code generator will fixup the locking in
3361                  * that case.
3362                  */
3363                 if ((d->d_ScopeFlags & SCOPE_LVALUE) &&
3364                     (stype->ty_Op == TY_PTRTO || stype->ty_Op == TY_REFTO)) {
3365                         int scope1;
3366                         int scope2;
3367
3368                         scope1 = d->d_ScopeFlags & (SCOPE_UNLOCKED |
3369                                                     SCOPE_HARD);
3370                         if (d->d_Id == String_This) {
3371                                 /* XXX temporarily ignore e.g. ptr.new() */
3372                                 scope2 = scope1;
3373                         } else if (scan->ex_Decl) {
3374                                 scope2 = scan->ex_Decl->d_ScopeFlags &
3375                                          (SCOPE_UNLOCKED | SCOPE_HARD);
3376                         } else {
3377                                 scope2 = SCOPE_UNLOCKED;
3378                         }
3379                         if (scope1 != scope2) {
3380                                 fprintf(stderr, "scopes: %08x, %08x\n",
3381                                         scope1, scope2);
3382                                 if (d->d_Id == String_This) {
3383                                         ExpFatalError(scan,
3384                                               TOK_ERR_SCOPE_MISMATCH_THIS);
3385                                 } else {
3386                                         ExpFatalError(scan,
3387                                               TOK_ERR_SCOPE_MISMATCH);
3388                                 }
3389                         }
3390                 }
3391 #endif
3392
3393                 /*
3394                  * accounting
3395                  */
3396                 d = RUNE_NEXT(d, d_Node);
3397                 pscan = &scan->ex_Next;
3398         }
3399
3400         /*
3401          * Make sure the caller knows its a var-args function even if
3402          * we didn't supply any additional args.  Otherwise the backend
3403          * may not generate the correct form for calls to the target.
3404          */
3405         if (varargs == 0 &&
3406             (sg2->sg_Flags & SGF_VARARGS)) {
3407                 sg2 = DupSemGroup(sg2->sg_Parent, NULL, sg2, 1);
3408                 varargs = 1;
3409         }
3410
3411         /*
3412          * Resolve the varargs sg2 after building it.
3413          */
3414         if (varargs) {
3415                 if (resolveSemGroup1(sg2, flags) &&
3416                     resolveSemGroup2(sg2, flags)) {
3417                         resolveSemGroup3(sg2, flags);
3418                 }
3419                 /* resolveStorageSemGroupAlign(sg2); */
3420                 /*resolveStorageSemGroup(sg2, 0, 0);*/
3421         }
3422
3423         /*
3424          * If we made a var-args call, adjust the expression's type
3425          */
3426         if (varargs) {
3427                 dassert(type->ty_Op == TY_ARGS);
3428                 exp->ex_Type = RESOLVETYPE(TypeToVarType(type, sg2));
3429         }
3430         if (isconst)
3431                 exp->ex_Flags |= EXF_PROBCONST;
3432
3433         exp->ex_Flags |= EXF_RESOLVED;
3434         return(exp);
3435 }
3436
3437 /*
3438  * resolveExpCast() - Cast the expression to the specified type and return
3439  *                    the cast expression.
3440  *
3441  *      Note that expression nodes depend on their ex_Type being correct,
3442  *      and also expressions may be shared, so be careful not to modify the
3443  *      ex_Type (or anything else) in the existing expression.
3444  *
3445  *      This code is somewhat different then resolveExpOper() and friends.
3446  *      The Exp argument has already been resolved so do not resolve it
3447  *      again, and the cast type already has SF_LVALUE set or cleared as
3448  *      appropriate (had better be cleared!)
3449  *
3450  *      As with operators we have to locate the cast declaration matching
3451  *      the cast we want to do.
3452  */
3453 static Exp *
3454 resolveExpCast(SemGroup *isg, SemGroup *sg, Exp *exp, Type *ltype, int flags)
3455 {
3456         Type *rtype;
3457         Declaration *d;
3458
3459         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
3460
3461         rtype = exp->ex_Type;
3462         dassert(rtype && ltype);
3463         /*
3464          * XXX attempt to cast from subclass to superclass?
3465          */
3466
3467         /*
3468          * XXX look in our local semantic hierarchy for a compatible cast ?
3469          */
3470
3471         /*
3472          * Look in the right hand (source) type for the cast
3473          */
3474         d = findCast(rtype, ltype, rtype, flags);
3475
3476         /*
3477          * If that fails then look in the left hand (destination) type for
3478          * the cast.
3479          */
3480         if (d == NULL) {
3481                 d = findCast(ltype, ltype, rtype, flags);
3482         }
3483 #if 1
3484         if (d == NULL && (rtype->ty_Op == TY_PTRTO ||
3485                           rtype->ty_Op == TY_REFTO ||
3486                           rtype->ty_Op == TY_CPTRTO)) {
3487                 d = findCast(&PointerType, ltype, rtype, flags);
3488         }
3489 #endif
3490
3491         if (d == NULL) {
3492                 /*
3493                  * We could not find a specific cast operator.  There are
3494                  * some inherent casts that we can do.  We run through these
3495                  * in attempt to come up with matching types.
3496                  */
3497                 if (ltype->ty_Op != rtype->ty_Op &&
3498                     (ltype->ty_Op == TY_PTRTO || ltype->ty_Op == TY_CPTRTO ||
3499                     ltype->ty_Op == TY_ARYOF) &&
3500                     (rtype->ty_Op == TY_PTRTO || rtype->ty_Op == TY_CPTRTO ||
3501                     rtype->ty_Op == TY_ARYOF)) {
3502                         /*
3503                          * Pointers, C pointers, or arrays can be cast to
3504                          * pointers, C pointers, or arrays of the same type.
3505                          *
3506                          * Cast the right hand type to an equivalent
3507                          * pointer/cpointer/array of the right hand type
3508                          * and re-resolve the cast.
3509                          */
3510                         exp = ExpToCastExp(exp,
3511                                 RESOLVETYPE(ChangeType(rtype, ltype->ty_Op)));
3512                         return(resolveExpCast(isg, sg, exp, ltype, flags));
3513                 } else if (MatchType(ltype, rtype) <= SG_COMPAT_PART) {
3514                         /*
3515                          * If the types are compatible (casting rtype->ltype),
3516                          * we can cast trivially.
3517                          */
3518                         exp = ExpToCastExp(exp, ltype);
3519                 } else if (MatchType(&NumericType, ltype) <= SG_COMPAT_PART &&
3520                            MatchType(&NumericType, rtype) <= SG_COMPAT_PART) {
3521                         /*
3522                          * Casting from one numeric type to another must be
3523                          * supported by the interpreter/compiler.
3524                          */
3525                         exp = ExpToCastExp(exp, ltype);
3526                 } else if (SimilarType(&VoidType, ltype)) {
3527                         /*
3528                          * Casting anything to void is allowed (throwing the
3529                          * object away).  E.g. statement-expressions.
3530                          */
3531                         exp = ExpToCastExp(exp, ltype);
3532                 } else if (SimilarType(&VoidPtrType, ltype)) {
3533                         /*
3534                          * Casting a pointer to a (void *) is trivial, but is
3535                          * only allowed if the underlying structure does not
3536                          * contain any pointers.
3537                          *
3538                          * NOTE: Generally only used when a pointer is being
3539                          *       cast to an integer.  Rune does not allow
3540                          *       casting back to other pointer types.
3541                          *
3542                          * XXX validate integral # of objects fit in pointer
3543                          * range.
3544                          */
3545                         if (rtype->ty_PtrType.et_Type->ty_Flags & TF_HASLVPTR)
3546                                 ExpFatalError(exp, TOK_ERR_LIMITED_VOIDP_CAST);
3547                         exp = ExpToCastExp(exp, ltype);
3548                 } else if (SimilarType(&VoidRefType, ltype)) {
3549                         /*
3550                          * Casting a pointer to a (void @) is trivial.
3551                          *
3552                          * NOTE: Generally only used when a pointer is being
3553                          *       cast to an integer.  Rune does not allow
3554                          *       casting back to other pointer types.
3555                          *
3556                          * XXX validate integral # of objects fit in pointer
3557                          * range.
3558                          */
3559                         if (rtype->ty_PtrType.et_Type->ty_Flags & TF_HASLVPTR)
3560                                 ExpFatalError(exp, TOK_ERR_LIMITED_VOIDP_CAST);
3561                         exp = ExpToCastExp(exp, ltype);
3562                 } else if (SimilarType(rtype, &VoidPtrType)) {
3563                         /*
3564                          * Casting from a void pointer may not be trivial
3565                          * but we leave it up to the interpreter/compiler.
3566                          *
3567                          * Only allow if the target does not contain any
3568                          * pointers or if the right-hand-side is NULL.
3569                          *
3570                          * XXX validate integral # of objects fit in pointer
3571                          * range.
3572                          */
3573                         switch(ltype->ty_Op) {
3574                         case TY_REFTO:
3575                         case TY_PTRTO:
3576                                 if ((exp->ex_Flags & EXF_NULL) == 0 &&
3577                                     (ltype->ty_PtrType.et_Type->ty_Flags &
3578                                      TF_HASLVPTR)) {
3579                                         ExpFatalError(exp, TOK_ERR_LIMITED_VOIDP_CAST);
3580                                 }
3581                                 break;
3582                         default:
3583                                 break;
3584                         }
3585                         exp = ExpToCastExp(exp, ltype);
3586                 } else if (SimilarType(rtype, &CVoidPtrType)) {
3587                         switch(ltype->ty_Op) {
3588                         case TY_CPTRTO:
3589                                 if ((exp->ex_Flags & EXF_NULL) == 0 &&
3590                                     (ltype->ty_PtrType.et_Type->ty_Flags &
3591                                      TF_HASLVPTR)) {
3592                                         ExpFatalError(exp, TOK_ERR_LIMITED_VOIDP_CAST);
3593                                 }
3594                                 break;
3595                         default:
3596                                 break;
3597                         }
3598                 } else if (SimilarType(ltype, &BoolType) &&
3599                            (rtype->ty_Op == TY_PTRTO ||
3600                             rtype->ty_Op == TY_REFTO ||
3601                             rtype->ty_Op == TY_CPTRTO)) {
3602                         /*
3603                          * Any pointer can be cast to a boolean, which
3604                          * tests against NULL.
3605                          */
3606                         exp = ExpToCastExp(exp, ltype);
3607                 } else if (ltype->ty_Op == rtype->ty_Op &&
3608                            (ltype->ty_Op == TY_PTRTO ||
3609                             ltype->ty_Op == TY_CPTRTO ||
3610                             ltype->ty_Op == TY_ARYOF)) {
3611                         /*
3612                          * We allow casts of pointers to similar numeric
3613                          * types if they are the same size, though this is
3614                          * really rather a hack.  This is mainly to handle
3615                          * the signed<->unsigned cast case.  XXX
3616                          */
3617                         int ok = 0;
3618
3619                         switch(ltype->ty_Op) {
3620                         case TY_PTRTO:
3621                                 if ((ltype->ty_PtrType.et_Type->ty_SQFlags &
3622                                      SF_CONST) == 0 &&
3623                                     (rtype->ty_PtrType.et_Type->ty_SQFlags &
3624                                      SF_CONST) != 0) {
3625                                         ExpFatalError(exp, TOK_ERR_READONLY);
3626                                 }
3627
3628                                 if (MatchType(&NumericType,
3629                                               ltype->ty_PtrType.et_Type) <=
3630                                      SG_COMPAT_SUBCLASS &&
3631                                     MatchType(&NumericType,
3632                                               rtype->ty_PtrType.et_Type) <=
3633                                      SG_COMPAT_SUBCLASS &&
3634                                     ltype->ty_Bytes == rtype->ty_Bytes
3635                                 ) {
3636                                         exp = ExpToCastExp(exp, ltype);
3637                                         ok = 1;
3638                                 }
3639                                 break;
3640                         case TY_CPTRTO:
3641                                 if ((ltype->ty_CPtrType.et_Type->ty_SQFlags &
3642                                      SF_CONST) == 0 &&
3643                                     (rtype->ty_CPtrType.et_Type->ty_SQFlags &
3644                                      SF_CONST) != 0) {
3645                                         ExpFatalError(exp, TOK_ERR_READONLY);
3646                                 }
3647                                 if (MatchType(&NumericType,
3648                                               ltype->ty_CPtrType.et_Type) <=
3649                                      SG_COMPAT_SUBCLASS &&
3650                                     MatchType(&NumericType,
3651                                               rtype->ty_CPtrType.et_Type) <=
3652                                      SG_COMPAT_SUBCLASS &&
3653                                     ltype->ty_Bytes == rtype->ty_Bytes
3654                                 ) {
3655                                         exp = ExpToCastExp(exp, ltype);
3656                                         ok = 1;
3657                                 }
3658                                 break;
3659                         case TY_ARYOF:
3660                                 if ((ltype->ty_AryType.et_Type->ty_SQFlags &
3661                                      SF_CONST) == 0 &&
3662                                     (rtype->ty_AryType.et_Type->ty_SQFlags &
3663                                      SF_CONST) != 0) {
3664                                         ExpFatalError(exp, TOK_ERR_READONLY);
3665                                 }
3666                                 if (MatchType(&NumericType,
3667                                               ltype->ty_AryType.et_Type) <=
3668                                      SG_COMPAT_SUBCLASS &&
3669                                     MatchType(&NumericType,
3670                                               rtype->ty_AryType.et_Type) <=
3671                                      SG_COMPAT_SUBCLASS &&
3672                                     ltype->ty_Bytes == rtype->ty_Bytes
3673                                 ) {
3674                                         exp = ExpToCastExp(exp, ltype);
3675                                         ok = 1;
3676                                 }
3677                                 break;
3678                         }
3679                         if (ok == 0) {
3680                                 fprintf(stderr,
3681                                         "Unable to resolve cast from pointers "
3682                                         "to dissimilar numeric types "
3683                                         "%s to %s\n",
3684                                         TypeToStr(rtype, NULL),
3685                                         TypeToStr(ltype, NULL));
3686                                 dassert_exp(exp, 0);
3687                         }
3688                 } else {
3689                         fprintf(stderr,
3690                                 "Unable to resolve cast from %s to %s\n",
3691                                 TypeToStr(rtype, NULL),
3692                                 TypeToStr(ltype, NULL));
3693                         dassert_exp(exp, 0);
3694                 }
3695         } else if (d->d_ScopeFlags & SCOPE_INTERNAL) {
3696                 /*
3697                  * We found a cast operator and it is an internal operator
3698                  */
3699                 exp = ExpToCastExp(exp, ltype);
3700                 exp->ex_Decl = d;
3701         } else {
3702                 /*
3703                  * We found a cast operator and it is a Rune cast procedure.  We
3704                  * must convert the cast to a procedure call.  If we want
3705                  * resolveCompoundExp() to be able to generate a compatible
3706                  * procedure (in a subclass) we have to tell it about the
3707                  * procedure.
3708                  */
3709                 Exp *sexp;
3710
3711                 sexp = ExpToCompoundExp(exp, TOK_COMPOUND);
3712                 if (d->d_ProcDecl.ed_ProcBody == NULL)
3713                         sexp->ex_Decl = d;
3714                 sexp = resolveCompoundExp(isg, sg, sexp,
3715                               d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType,
3716                               flags);
3717                 exp = AllocExp(NULL);
3718                 exp->ex_Lhs = AllocExp(NULL);
3719                 exp->ex_Lhs->ex_Token = TOK_DECL;
3720                 exp->ex_Lhs->ex_Id = d->d_Id;
3721                 exp->ex_Lhs->ex_Decl = d;
3722                 exp->ex_Lhs->ex_Type = d->d_ProcDecl.ed_Type;
3723                 exp->ex_Lhs->ex_Flags |= EXF_RESOLVED;
3724                 exp->ex_Rhs  = sexp;
3725                 exp->ex_Flags |= EXF_BINARY;
3726                 exp->ex_Token = TOK_CALL;
3727                 /* XXX use ltype or procedure's rettype? */
3728                 exp->ex_Type = ltype;
3729                 LexDupRef(&sexp->ex_LexRef, &exp->ex_LexRef);
3730                 LexDupRef(&sexp->ex_LexRef, &exp->ex_Lhs->ex_LexRef);
3731         }
3732         exp->ex_Flags |= EXF_RESOLVED;
3733         return(exp);
3734 }
3735
3736 static
3737 Declaration *
3738 findCast(Type *btype, Type *ltype, Type *rtype, int flags)
3739 {
3740         SemGroup *sg;
3741         Declaration *d;
3742
3743         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
3744
3745         /*
3746          * Locate the base type.  If the base type does not have a SemGroup
3747          * there are no casts.  (XXX put system operators here)
3748          */
3749         sg = BaseType(&btype);
3750
3751         if (sg == NULL)
3752                 return(NULL);
3753
3754         /*
3755          * Look for the cast in the SemGroup
3756          */
3757         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
3758                 if (d->d_Op == DOP_PROC && (d->d_ScopeFlags & SCOPE_CAST)) {
3759                         if (MatchCastTypes(d, ltype, rtype))
3760                                 return(d);
3761                 }
3762         }
3763
3764         /*
3765          * Failed.  If the base type is a compound type, look for the
3766          * cast in the SemGroup for each element making up the compound
3767          * type.  e.g. so (mycustomtype, double) would find the cast
3768          * in mycustomtype.
3769          */
3770         if (btype->ty_Op == TY_COMPOUND) {
3771                 RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
3772                         Declaration *d2;
3773                         if (d->d_Op & DOPF_STORAGE) {
3774                                 d2 = findCast(d->d_StorDecl.ed_Type,
3775                                               ltype, rtype, flags);
3776                         } else if (d->d_Op == DOP_TYPEDEF) {
3777                                 d2 = findCast(d->d_TypedefDecl.ed_Type,
3778                                               ltype, rtype, flags);
3779                         } else {
3780                                 d2 = NULL;
3781                         }
3782                         if (d2)
3783                                 return(d2);
3784                 }
3785         }
3786         return(NULL);
3787 }
3788
3789
3790 /*
3791  * resolveExpOper() - resolve an operator
3792  *
3793  *      This is complex enough that it is broken out into its own procedure.
3794  *      Normally we just look the operator up but we have to special case
3795  *      pointer arithmatic because we do will not know until now that we
3796  *      have to do it.
3797  *
3798  *      itype is a return-type hint only.  resolveExpOper() can ignore it
3799  *      if it wishes.  We currently use it to detect cast-to-void, such as
3800  *      when an expression like "++i" is used in a for() loop or as a
3801  *      standalone statement.  This allows us to optimize the case.
3802  */
3803 static Exp *
3804 resolveExpOper(SemGroup *isg, SemGroup *sg, Exp *exp, Type *itype, int flags)
3805 {
3806         Declaration *d;
3807         int isPointerOp = 0;
3808         Exp copy;
3809
3810         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
3811
3812         loadExpCopy(&copy, exp);
3813         dassert_exp(exp, exp->ex_Id != NULL);
3814         if (exFlags & EXF_BINARY) {
3815                 exLhs = resolveExp(isg, sg, exLhs, NULL, flags);
3816                 exRhs = resolveExp(isg, sg, exRhs, NULL, flags);
3817         } else if (exFlags & EXF_UNARY) {
3818                 exLhs = resolveExp(isg, sg, exLhs, NULL, flags);
3819         } else {
3820                 dassert_exp(exp, 0);
3821         }
3822
3823         /*
3824          * If the lhs is a pointer look the operator up in the Pointer
3825          * class first.  Operators in the Pointer class are special-cased.
3826          * A second pointer argument or a pointer return value must match
3827          * the lhs pointer.
3828          *
3829          * If this fails, or if the ltype is not a pointer, then look
3830          * the operator up normally.
3831          */
3832         if (exLhs->ex_Type->ty_Op == TY_PTRTO ||
3833             exLhs->ex_Type->ty_Op == TY_REFTO ||
3834             exLhs->ex_Type->ty_Op == TY_CPTRTO
3835         ) {
3836                 Type *ltype;
3837                 Type *rtype;
3838
3839                 if (exFlags & EXF_BINARY) {
3840                         rtype = exRhs->ex_Type;
3841                         ltype = exLhs->ex_Type;
3842                 } else {
3843                         dassert(exFlags & EXF_UNARY);
3844                         rtype = NULL;
3845                         ltype = exLhs->ex_Type;
3846                 }
3847                 d = findOper(&PointerType, exp->ex_Id, ltype, rtype, flags);
3848                 if (d)
3849                         isPointerOp = 1;
3850                 else
3851                         d = findExpOper(&copy, flags);
3852         } else {
3853                 d = findExpOper(&copy, flags);
3854         }
3855
3856         /*
3857          * Fall through to finish up resolving the operator.  We just set
3858          * ex_Decl for internal operators, and construct a call for
3859          * non-internal procedural operators.
3860          */
3861         if (d) {
3862                 Declaration *d2;
3863                 Type *type;
3864                 SemGroup *sg2;
3865                 int count = 0;
3866
3867                 dassert_exp(exp, d != NULL);
3868                 dassert_exp(exp, d->d_Op == DOP_PROC);
3869                 dassert_exp(exp, d->d_ProcDecl.ed_Type->ty_Op == TY_PROC);
3870                 type = d->d_ProcDecl.ed_Type;
3871                 exType = type->ty_ProcType.et_RetType;
3872
3873                 /*
3874                  * Special case for internal Pointer ops.  The return type is
3875                  * the left-hand type (we may still optimize it to void later).
3876                  */
3877                 if (isPointerOp &&
3878                     (d->d_ScopeFlags & SCOPE_INTERNAL) && 
3879                     SimilarType(&VoidRefType, exType)
3880                 ) {
3881                         if (exType->ty_SQFlags & SF_LVALUE)
3882                                 exType = ADD_LVALUE(exLhs->ex_Type);
3883                         else
3884                                 exType = DEL_LVALUE(exLhs->ex_Type);
3885                 }
3886
3887                 type = d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType;
3888                 dassert(type->ty_Op == TY_ARGS);
3889                 sg2 = type->ty_ArgsType.et_SemGroup;
3890
3891                 /*
3892                  * Assert that LVALUE requirements are met.  XXX MatchType()
3893                  * code should disallow the non-lvalue-cast-to-lvalue case
3894                  * so we don't have to do a check here.
3895                  */
3896                 RUNE_FOREACH(d2, &sg2->sg_DeclList, d_Node) {
3897                         if ((d2->d_Op & DOPF_STORAGE) &&
3898                             d2->d_Op != DOP_GLOBAL_STORAGE) {
3899                                 if (count == 0) {
3900                                         if ((d2->d_ScopeFlags & SCOPE_LVALUE) &&
3901                                             (exLhs->ex_Type->ty_SQFlags &
3902                                              SF_LVALUE) == 0
3903                                         ) {
3904                                                 fprintf(stderr,
3905                                                         "lhs of exp must be "
3906                                                         "lvalue\n");
3907                                                 dassert_exp(exp, 0);
3908                                         }
3909                                 } else if (count == 1) {
3910                                         if ((d2->d_ScopeFlags & SCOPE_LVALUE) &&
3911                                                 (exRhs->ex_Type->ty_SQFlags &
3912                                                  SF_LVALUE) == 0
3913                                         ) {
3914                                                 fprintf(stderr,
3915                                                         "rhs of exp must be "
3916                                                         "lvalue\n");
3917                                                 dassert_exp(exp, 0);
3918                                         }
3919                                 }
3920                                 ++count;
3921                         }
3922                 }
3923
3924                 if (d->d_ScopeFlags & SCOPE_INTERNAL) {
3925                         /*
3926                          * Internal operator.  Optimize any cast to void
3927                          * by having the internal function deal with it.
3928                          * (since we aren't setting exType the optimization
3929                          * currently doesn't do anything, see ST_Exp)
3930                          */
3931                         exDecl = d;
3932                         if (itype == &VoidType) {
3933                                 /*exType = itype;*/
3934                                 exFlags |= EXF_RET_VOID;
3935                         }
3936                 } else {
3937                         /*
3938                          * Normal procedural operator.  Convert the left and
3939                          * right hand sides to a compound expression and
3940                          * convert exp to a TOK_CALL.  NOTE! ex_Rhs may be
3941                          * NULL (unary op).
3942                          *
3943                          * The compound expression may need to rewrite a
3944                          * subclass procedure, which it can do if the
3945                          * procedure's body has not yet been created (or
3946                          * duplicated from the superclass).  ex_Decl must
3947                          * be set in this case.
3948                          *
3949                          * Note that the expression structure may be shared.
3950                          * The conversion is permanent so that is ok.
3951                          *
3952                          * XXX keep the type intact?
3953                          */
3954                         exLhs->ex_Next = exRhs;
3955                         exRhs = exLhs;
3956                         exRhs = ExpToCompoundExp(exRhs, TOK_COMPOUND);
3957                         if (d->d_ProcDecl.ed_ProcBody == NULL)
3958                                 exRhs->ex_Decl = d;
3959                         exRhs = resolveCompoundExp(isg, sg, exRhs, type, flags);
3960                         exLhs = AllocExp(NULL);
3961                         LexDupRef(&exp->ex_LexRef, &exLhs->ex_LexRef);
3962                         exLhs->ex_Token = TOK_ID;
3963                         exLhs->ex_Id = d->d_Id;
3964                         exLhs->ex_Decl = d;
3965                         exLhs->ex_Type = d->d_ProcDecl.ed_Type;
3966                         exLhs->ex_Flags |= EXF_RESOLVED;
3967                         exToken = exp->ex_Token = TOK_CALL;
3968                         exFlags = EXF_BINARY;
3969                 }
3970         }
3971         if (d == NULL) {
3972                 fprintf(stderr,
3973                         "Unable to resolve operator: %s\n", exp->ex_Id);
3974                 dassert_exp(exp, 0);
3975         }
3976
3977         /*
3978          * Flag a pure operator whos arguments are constants as probably
3979          * being constant.
3980          */
3981         if (d->d_ScopeFlags & SCOPE_PURE) {
3982                 if ((exLhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)) &&
3983                     (exRhs == NULL ||
3984                      (exRhs->ex_Flags & (EXF_CONST | EXF_PROBCONST)))) {
3985                         exFlags |= EXF_PROBCONST;
3986                 }
3987         }
3988
3989         exFlags |= EXF_RESOLVED;
3990         return(dupExpCopy(&copy, exp));
3991 }
3992
3993 static void
3994 loadExpCopy(Exp *copy, Exp *exp)
3995 {
3996         copy->ex_Lhs = exp->ex_Lhs;
3997         copy->ex_Rhs = exp->ex_Rhs;
3998         copy->ex_Flags = exp->ex_Flags;
3999         copy->ex_Type = exp->ex_Type;
4000         copy->ex_Decl = exp->ex_Decl;
4001         copy->ex_Token = exp->ex_Token;
4002         copy->ex_Visibility = exp->ex_Visibility;
4003         copy->ex_Id = exp->ex_Id;
4004         copy->ex_ArgId = exp->ex_ArgId;
4005         copy->ex_AuxExp = exp->ex_AuxExp;
4006 }
4007
4008 static void
4009 saveExpCopy(Exp *copy, Exp *exp)
4010 {
4011         exp->ex_Lhs = copy->ex_Lhs;
4012         exp->ex_Rhs = copy->ex_Rhs;
4013         exp->ex_Flags = copy->ex_Flags;
4014         exp->ex_Type = copy->ex_Type;
4015         exp->ex_Decl = copy->ex_Decl;
4016         exp->ex_Token = copy->ex_Token;
4017         exp->ex_Visibility = copy->ex_Visibility;
4018         exp->ex_Id = copy->ex_Id;
4019         exp->ex_ArgId = copy->ex_ArgId;
4020         exp->ex_AuxExp = copy->ex_AuxExp;
4021 }
4022
4023 #define EXF_DUPSHAREFLAGS       -1
4024
4025 static Exp *
4026 dupExpCopy(Exp *copy, Exp *exp)
4027 {
4028         Exp *nexp;
4029
4030         if ((exp->ex_Flags & EXF_DUPEXP) == 0) {
4031                 saveExpCopy(copy, exp);
4032                 return(exp);
4033         }
4034
4035         /*
4036          * We can share the expression or subexpression across duplicated
4037          * elements in distinct subclasses if these conditions are met.
4038          *
4039          * Note: 0x80000000 for ex_Visibility simply means that the visibility
4040          * was never modified and can be changed for the first time.
4041          * Superclasses are resolved first so we should be ok.
4042          */
4043         if (exp->ex_Lhs == copy->ex_Lhs &&
4044                 exp->ex_Rhs == copy->ex_Rhs &&
4045                 ((exp->ex_Flags ^ copy->ex_Flags) & ~EXF_DUPSHAREFLAGS) == 0 &&
4046                 (exp->ex_Type == copy->ex_Type || exp->ex_Type == NULL) &&
4047                 exp->ex_Token == copy->ex_Token &&
4048                 (exp->ex_Decl == copy->ex_Decl || exp->ex_Decl == NULL) &&
4049                 (exp->ex_Id == copy->ex_Id || exp->ex_Id == NULL) &&
4050                 (exp->ex_ArgId == copy->ex_ArgId || exp->ex_ArgId == NULL) &&
4051                 (exp->ex_AuxExp == copy->ex_AuxExp || exp->ex_AuxExp == NULL) &&
4052                 (exp->ex_Visibility == copy->ex_Visibility ||
4053                  (exp->ex_Visibility & 0x80000000))
4054         ) {
4055 #if DUPEXP_DEBUG
4056                 static int count;
4057                 fprintf(stderr, "DUPEXPB COMPARE %d %p\n", ++count, exp);
4058 #endif
4059                 saveExpCopy(copy, exp);
4060                 return(exp);
4061         } 
4062
4063         nexp = AllocExp(NULL);
4064         LexDupRef(&exp->ex_LexRef, &nexp->ex_LexRef);
4065
4066 #if DUPEXP_DEBUG
4067         {
4068                 static int count;
4069                 fprintf(stderr,
4070                         "DUPEXPB %d %p lhs (%p,%p) rhs (%p,%p) "
4071                         "flags (%08x,%08x) types (%p, %p) "
4072                         "tokens (%04x, %04x), decl (%p, %p) "
4073                         "vis (%d, %d)\n",
4074                         ++count,
4075                         exp,
4076                         exp->ex_Lhs, copy->ex_Lhs,
4077                         exp->ex_Rhs, copy->ex_Rhs,
4078                         exp->ex_Flags & ~EXF_DUPSHAREFLAGS,
4079                         copy->ex_Flags & ~EXF_DUPSHAREFLAGS,
4080                         exp->ex_Type, copy->ex_Type,
4081                         exp->ex_Token, copy->ex_Token,
4082                         exp->ex_Decl, copy->ex_Decl,
4083                         exp->ex_Visibility, copy->ex_Visibility
4084                 );
4085                 ExpPrintError(exp, 0);
4086         }
4087 #endif
4088
4089         copy->ex_Flags &= ~EXF_DUPEXP;
4090         saveExpCopy(copy, nexp);
4091         nexp->u = exp->u;
4092         return(nexp);
4093 }
4094
4095 /*
4096  * resolveType() -      Resolve a type
4097  *
4098  *      This routine is responsible for resolving the size and alignment
4099  *      features of a type.  Note that we do not special-case LVALUE
4100  *      qualified types here.
4101  *
4102  *      This routine is also rsponsible for resolving the visibility of
4103  *      a type's elements.  Visibility is inherited from sub-types.  Base
4104  *      classes's visibility should already be set by resolveSuperClass()
4105  */
4106 Type *
4107 resolveType(Type *type, Type *adjtype, int flags)
4108 {
4109         SemGroup *sg = NULL;
4110         Type *otype = type;
4111         int do2 = 0;
4112
4113         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
4114
4115         if (type->ty_Flags & TF_RESOLVED)
4116                 return(type);
4117
4118         dassert_type(type, (type->ty_Flags & TF_RESOLVING) == 0);
4119         type->ty_Flags |= TF_RESOLVING;
4120
4121         switch(type->ty_Op) {
4122         case TY_CLASS:
4123                 /*
4124                  * NOTE: TF_HASLVPTR inherited as appropriate after switch.
4125                  *
4126                  * NOTE: Special case, PointerType fields not in classes XXX
4127                  *       (force alignment and bytes)?
4128                  */
4129                 dassert(type->ty_SQList ==
4130                         &type->ty_ClassType.et_SemGroup->sg_ClassList);
4131                 sg = type->ty_ClassType.et_SemGroup;
4132                 do2 = resolveSemGroup1(sg, flags);
4133                 if (type != &PointerType) {
4134                         type->ty_Bytes = sg->sg_Bytes;
4135                         type->ty_AlignMask = sg->sg_AlignMask;
4136                 }
4137                 /* visibility already determined by resolveSuperClass? */
4138
4139                 if (type->ty_ClassType.et_Super &&
4140                     type->ty_ClassType.et_Super->ty_Op == TY_UNRESOLVED) {
4141                         type->ty_ClassType.et_Super =
4142                                 resolveSuperClass(type->ty_ClassType.et_Super);
4143                 }
4144
4145                 /*
4146                  * Type inherits ISUNSIGNED from class.  This is a special
4147                  * flag helper for the interpreter and code generator.
4148                  */
4149                 if (sg->sg_Flags & SGF_ISINTEGER)
4150                         type->ty_Flags |= TF_ISINTEGER;
4151                 if (sg->sg_Flags & SGF_ISUNSIGNED)
4152                         type->ty_Flags |= TF_ISUNSIGNED;
4153                 if (sg->sg_Flags & SGF_ISFLOATING)
4154                         type->ty_Flags |= TF_ISFLOATING;
4155                 if (sg->sg_Flags & SGF_ISBOOL)
4156                         type->ty_Flags |= TF_ISBOOL;
4157                 if (sg->sg_Flags & SGF_HASASS)
4158                         type->ty_Flags |= TF_HASASS;
4159                 dassert(type->ty_Visibility != 0);
4160                 break;
4161         case TY_CPTRTO:
4162                 /*
4163                  * NOTE: Do not set TF_HASLVPTR, C pointers are not tracked.
4164                  */
4165                 type->ty_Bytes = sizeof(void *);
4166                 type->ty_AlignMask = POINTER_ALIGN;
4167                 type->ty_CPtrType.et_Type =
4168                         RESOLVETYPEADJ(type->ty_CPtrType.et_Type, type);
4169                 type->ty_Visibility = type->ty_CPtrType.et_Type->ty_Visibility;
4170                 break;
4171         case TY_PTRTO:
4172                 /*
4173                  * Set TF_HASLVPTR, pointers are tracked.
4174                  */
4175                 type->ty_Bytes = sizeof(PointerStor);
4176                 type->ty_AlignMask = POINTER_ALIGN;
4177                 type->ty_PtrType.et_Type =
4178                         RESOLVETYPEADJ(type->ty_PtrType.et_Type, type);
4179                 type->ty_Visibility = type->ty_PtrType.et_Type->ty_Visibility;
4180                 type->ty_Flags |= TF_HASLVPTR;
4181                 break;
4182         case TY_REFTO:
4183                 /*
4184                  * Set TF_HASLVPTR, references are tracked.
4185                  */
4186                 type->ty_Bytes = sizeof(PointerStor);
4187                 type->ty_AlignMask = POINTER_ALIGN;
4188                 type->ty_RefType.et_Type =
4189                         RESOLVETYPEADJ(type->ty_RefType.et_Type, type);
4190                 type->ty_Visibility = type->ty_RefType.et_Type->ty_Visibility;
4191                 type->ty_Flags |= TF_HASLVPTR;
4192                 break;
4193         case TY_ARYOF:
4194                 /*
4195                  * Inherit TF_HASLVPTR (if array type is or contains something
4196                  * which needs to be tracked).
4197                  *
4198                  * XXX allow ArySize resolve to local expression?
4199                  * XXX use interpreter to resolve constant expression?
4200                  * XXX SemGroup passed as NULL.
4201                  *
4202                  * XXX hack, ex_ArySize can be shared amoungst qualified
4203                  *     array types.  Only resolve it once.  XXX
4204                  *
4205                  * YYY hack what is our ImportSemGroup ???
4206                  */
4207                 {
4208                         Exp *exp = type->ty_AryType.et_ArySize;
4209                         if ((exp->ex_Flags & EXF_RESOLVED) == 0) {
4210                                 exp = resolveConstExp(NULL,
4211                                                  type->ty_AryType.et_SemGroup,
4212                                                  exp, flags);
4213                         }
4214                         type->ty_AryType.et_ArySize = exp;
4215                         type->ty_AryType.et_Type =
4216                                 RESOLVETYPEADJ(type->ty_AryType.et_Type, type);
4217                         type->ty_AryType.et_Count = resolveGetConstExpInt64(exp);
4218                         type->ty_AlignMask =
4219                                 type->ty_AryType.et_Type->ty_AlignMask;
4220                         type->ty_Bytes =
4221                                 type->ty_AryType.et_Type->ty_Bytes *
4222                                 type->ty_AryType.et_Count;
4223                 }
4224                 type->ty_Visibility = type->ty_AryType.et_Type->ty_Visibility;
4225                 type->ty_Flags |= type->ty_AryType.et_Type->ty_Flags &
4226                                   (TF_HASLVPTR | TF_HASCONSTRUCT |
4227                                    TF_HASDESTRUCT | TF_HASGCONSTRUCT |
4228                                    TF_HASGDESTRUCT | TF_HASASS);
4229                 break;
4230         case TY_COMPOUND:
4231                 /*
4232                  * NOTE: TF_HASLVPTR inherited as appropriate after switch.
4233                  */
4234                 sg = type->ty_CompType.et_SemGroup;
4235                 do2 = resolveSemGroup1(sg, flags);
4236                 type->ty_Bytes = sg->sg_Bytes;
4237                 type->ty_AlignMask = sg->sg_AlignMask;
4238                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4239                 break;
4240         case TY_VAR:
4241                 /*
4242                  * NOTE: TF_HASLVPTR inherited as appropriate after switch.
4243                  */
4244                 sg = type->ty_VarType.et_SemGroup;
4245                 do2 = resolveSemGroup1(sg, flags);
4246                 type->ty_Bytes = sg->sg_Bytes;
4247                 type->ty_AlignMask = sg->sg_AlignMask;
4248                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4249                 break;
4250         case TY_ARGS:
4251                 /*
4252                  * NOTE: TF_HASLVPTR inherited as appropriate after switch.
4253                  */
4254                 sg = type->ty_ArgsType.et_SemGroup;
4255                 do2 = resolveSemGroup1(sg, flags);
4256                 type->ty_Bytes = sg->sg_Bytes;
4257                 type->ty_AlignMask = sg->sg_AlignMask;
4258                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4259                 break;
4260         case TY_PROC:
4261                 /*
4262                  * NOTE: Storage not tracked.
4263                  */
4264                 type->ty_ProcType.et_ArgsType =
4265                         RESOLVETYPE(type->ty_ProcType.et_ArgsType);
4266                 type->ty_ProcType.et_RetType =
4267                         RESOLVETYPEADJ(type->ty_ProcType.et_RetType, type);
4268                 type->ty_Bytes = 0;
4269                 type->ty_AlignMask = 0;
4270                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4271                 break;
4272         case TY_STORAGE:
4273                 /*
4274                  * NOTE: Base storage is not tracked.
4275                  */
4276                 type->ty_Bytes = type->ty_StorType.et_Bytes;
4277                 /* XXX check pwr of 2 */
4278                 if (type->ty_Bytes)
4279                         type->ty_AlignMask = type->ty_Bytes - 1;
4280                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4281                 break;
4282         case TY_UNRESOLVED:
4283                 /*
4284                  * NOTE: Tracking set by resolveType().
4285                  */
4286                 type->ty_Flags &= ~TF_RESOLVING;
4287                 type = resolveSuperClass(type);
4288                 if (type == NULL) {
4289                         errorDottedId(otype->ty_UnresType.et_DottedId,
4290                                       "Unable to resolve class");
4291                         dpanic("");
4292                         /* NOT REACHED */
4293                 }
4294                 type = RESOLVETYPE(type);
4295                 type->ty_Flags |= TF_RESOLVING;
4296                 /* visibility set by resolveSuperClass() */
4297                 break;
4298         case TY_DYNAMIC:
4299                 /*
4300                  * NOTE: Tracking unknown (must be handled at run-time).
4301                  */
4302                 type->ty_Visibility = SCOPE_ALL_VISIBLE;
4303                 break;
4304         case TY_IMPORT:
4305                 /*
4306                  * NOTE: Storage is persistent, so wrapper is not tracked.
4307                  */
4308                 type->ty_Visibility = SCOPE_ALL_VISIBLE;        /* XXX */
4309                 break;
4310         default:
4311                 dpanic("Unknown type %d (type=%p)", type->ty_Op, type);
4312                 break;
4313         }
4314         type->ty_Flags &= ~TF_RESOLVING;
4315         type->ty_Flags |= TF_RESOLVED;
4316         if (do2 && sg) {
4317                 do2 = resolveSemGroup2(sg, flags);
4318                 if (do2)
4319                         resolveSemGroup3(sg, flags);
4320         }
4321
4322         /*
4323          * Resolve tracking flags so the run-time can take appropriate
4324          * action.
4325          */
4326         if (sg) {
4327                 if (sg->sg_Flags & SGF_HASASS)
4328                         type->ty_Flags |= TF_HASASS;
4329                 if (sg->sg_SRBase)
4330                         type->ty_Flags |= TF_HASLVPTR;
4331                 if (sg->sg_Flags & SGF_VARARGS)
4332                         type->ty_Flags |= TF_HASLVPTR;  /* XXX TF_VARARGS */
4333                 if (sg->sg_CBase)
4334                         type->ty_Flags |= TF_HASCONSTRUCT;
4335                 if (sg->sg_DBase)
4336                         type->ty_Flags |= TF_HASDESTRUCT;
4337                 /*
4338                  * Combine constructor/destructor hint flags for globals
4339                  * because we have just one linked list for global constructors
4340                  * and destructors (no need to optimize heavily).
4341                  */
4342                 if (sg->sg_GBase)
4343                         type->ty_Flags |= TF_HASGCONSTRUCT|TF_HASGDESTRUCT;
4344         }
4345
4346         /*
4347          * Resolve the default expression for the type, if any.
4348          *
4349          * XXX qualified types just copy the exp. bad bad YYY
4350          *
4351          * YYY resolveExp() no ISG (import sem group)
4352          */
4353         if (type->ty_AssExp) {
4354                 if ((type->ty_AssExp->ex_Flags & EXF_RESOLVED) == 0) {
4355                         type->ty_AssExp = resolveExp(NULL, sg, type->ty_AssExp,
4356                                                      DEL_LVALUE(type),
4357                                                      flags | RESOLVE_AUTOCAST);
4358                 }
4359                 type->ty_Flags |= TF_HASASS;
4360         }
4361
4362         /*
4363          * If adjtype is non-NULL it must be moved to the new type's QList.
4364          */
4365         if (adjtype && type != otype) {
4366                 if (adjtype->ty_SQList)
4367                         RUNE_REMOVE(adjtype->ty_SQList, adjtype, ty_Node);
4368                 adjtype->ty_SQList = &type->ty_QList;
4369                 RUNE_INSERT_TAIL(adjtype->ty_SQList, adjtype, ty_Node);
4370         }
4371
4372         /*
4373          * ty_DynamicVector is nominally used when a Rune binary is run, but
4374          * we also need to set up enough of it such that mixed interpretation
4375          * and execution, or even just straight interpretation, works.  This
4376          * is because the interpreter calls into libruntime.
4377          */
4378         type->ty_DynamicVector = DefaultDynamicVector;
4379
4380         /*
4381          * Internal types may be implied during resolution, be sure to
4382          * completely resolve its alignment too.
4383          *
4384          * (If not internal we have to wait because there might be recursive
4385          * dependencies on the type).
4386          */
4387         if (type->ty_Flags & TF_ISINTERNAL) {
4388                 runesize_t dummy = 0;
4389                 resolveStorageTypeExpAlign(type, &dummy, 0);
4390         }
4391
4392         return(type);
4393 }
4394
4395 /*
4396  * resolveSuperClass() - resolve an unresolved dotted id sequence into a class
4397  *
4398  *      Unresolved type identifier sequences must be resolved.  We are also
4399  *      responsible for setting the visibility of the type's elements.
4400  */
4401 Type *
4402 resolveSuperClass(Type *super)
4403 {
4404         string_t *dottedId;
4405         SemGroup *sg;
4406         Declaration *d;
4407         int visibility = SCOPE_ALL_VISIBLE;
4408         int eno = 0;
4409
4410         dassert_type(super, super->ty_Op == TY_UNRESOLVED);
4411
4412         dottedId = super->ty_UnresType.et_DottedId;
4413         sg = super->ty_UnresType.et_SemGroup;
4414
4415         d = FindDeclPath(NULL, super->ty_UnresType.et_ImportSemGroup,
4416                          sg, super,
4417                          dottedId, FDC_NULL, &visibility, -1, &eno);
4418         if (d == NULL)
4419                 return(NULL);
4420
4421         /*
4422          * Resolve the unresolved type.  Note that this occurs during class
4423          * resolution and we can't call resolveType() here without getting into
4424          * a loop, so we do not yet know storage requirements (ty_Bytes and
4425          * ty_Align).
4426          */
4427         switch(d->d_Op) {
4428         case DOP_CLASS:
4429                 sg = d->d_ClassDecl.ed_SemGroup;
4430                 super->ty_Op = TY_CLASS;
4431                 super->ty_ClassType.et_SemGroup = sg;
4432                 super->ty_ClassType.et_Super = d->d_ClassDecl.ed_Super;
4433                 super->ty_Visibility = visibility;
4434                 if (super->ty_SQList)
4435                         RUNE_REMOVE(super->ty_SQList, super, ty_Node);
4436                 super->ty_SQList = &sg->sg_ClassList;
4437                 RUNE_INSERT_TAIL(super->ty_SQList, super, ty_Node);
4438                 dassert(visibility);
4439                 /*
4440                  * XXX should we move the class from the unresolved list to
4441                  * the new SemGroup's actual list?
4442                  */
4443                 break;
4444         case DOP_TYPEDEF:
4445                 /*
4446                  * Adjust super instead of allocating a new super, so all
4447                  * other references to super using this class path get
4448                  * resolved too.
4449                  */
4450                 {
4451                         dassert_type(super, d->d_TypedefDecl.ed_Type != super);
4452                         TypeToQualType(
4453                                 d->d_TypedefDecl.ed_Type,
4454                                 super,
4455                                 super->ty_SQFlags |
4456                                  d->d_TypedefDecl.ed_Type->ty_SQFlags,
4457                                 super->ty_AssExp
4458                         );
4459                 }
4460                 super->ty_Visibility = visibility;
4461                 break;
4462         default:
4463                 errorDottedId(dottedId, "identifier is not a class or typedef");
4464                 dassert_type(super, 0);
4465         }
4466         return(super);
4467 }
4468
4469 /*
4470  * Resolve the declarations in a semantic group.  We have to do this if
4471  * (a) The declaration(s) would not otherwise be resolved by our statement
4472  * scan, or (b) We need definitive size/alignment information now rather
4473  * then later.
4474  *
4475  * Also resolve SemGroup global initialization dependencies via SemGroupDepend.
4476  *
4477  * SemGroup resolution occurs in three stages in order to deal with
4478  * resolver loops.  The first stage does just enough to figure out
4479  * how large the non-global part of the SemGroup is (e.g. doesn't run
4480  * through pointers).  The second stage handles global elements, and the
4481  * third stage completes the process.
4482  *
4483  * NOTE!  This code does not resolve declarations related to executable
4484  * semantic groups, such as sub-blocks within a procedure, but it does
4485  * have to resolve procedure definitions found in Class's and such.
4486  *
4487  * NOTE!  This code handles the last stage of subclass refinement, by 
4488  * checking the validity of the refinement and setting sg_Compat properly.
4489  */
4490 static
4491 int
4492 resolveSemGroup1(SemGroup *sg, int flags)
4493 {
4494         SemGroup *dep;
4495         Declaration *d;
4496         Type *type;
4497
4498         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
4499
4500         dep = resolvePushSGDepend(sg);
4501         if (sg->sg_Flags & SGF_RESOLVED) {
4502                 resolvePopSGDepend(dep);
4503                 return(0);
4504         }
4505         if (sg->sg_Flags & SGF_RESOLVING) {
4506                 fprintf(stderr,
4507                         "Unable to resolve embedded recursive reference\n");
4508                 dassert_semgrp(sg, (sg->sg_Flags & SGF_RESOLVING) == 0);
4509         }
4510         sg->sg_Flags |= SGF_RESOLVING;
4511
4512         /*
4513          * First pass - resolve storage only.  Note that this specifically
4514          * does not try to handle the multiple semantic layers inside a
4515          * procedure.  See ResolveStorage() for that.
4516          */
4517         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
4518                 switch(d->d_Op) {
4519                 case DOP_CLASS:
4520                 case DOP_TYPEDEF:
4521                 case DOP_ALIAS:
4522                 case DOP_IMPORT:
4523                         break;
4524                 case DOP_PROC:
4525                         /*
4526                          * Deal with constructor/destructor chaining.
4527                          */
4528                         if (d->d_ScopeFlags & SCOPE_GLOBAL) {
4529                                 if ((d->d_Flags & DF_ONGLIST) == 0 &&
4530                                     (d->d_ScopeFlags & (SCOPE_CONSTRUCTOR |
4531                                                        SCOPE_DESTRUCTOR))) {
4532                                         d->d_GNext = d->d_MyGroup->sg_GBase;
4533                                         d->d_MyGroup->sg_GBase = d;
4534                                         d->d_Flags |= DF_ONGLIST;
4535                                 }
4536                         } else {
4537                                 if ((d->d_Flags & DF_ONCLIST) == 0 &&
4538                                     (d->d_ScopeFlags & SCOPE_CONSTRUCTOR)) {
4539                                         d->d_CNext = d->d_MyGroup->sg_CBase;
4540                                         d->d_MyGroup->sg_CBase = d;
4541                                         d->d_Flags |= DF_ONCLIST;
4542                                 }
4543                                 if ((d->d_Flags & DF_ONDLIST) == 0 &&
4544                                     (d->d_ScopeFlags & SCOPE_DESTRUCTOR)) {
4545                                         d->d_DNext = d->d_MyGroup->sg_DBase;
4546                                         d->d_MyGroup->sg_DBase = d;
4547                                         d->d_Flags |= DF_ONDLIST;
4548                                 }
4549                         }
4550                         break;
4551                 case DOP_STACK_STORAGE:
4552                         /*
4553                          * can't happen.  Stack storage is only used in
4554                          * executable contexts.
4555                          */
4556                         dassert_decl(d, 0);
4557                 case DOP_ARGS_STORAGE:
4558                 case DOP_GROUP_STORAGE:
4559                         type = d->d_StorDecl.ed_Type;
4560
4561                         switch(type->ty_Op) {
4562                         case TY_CPTRTO:
4563                                 d->d_Bytes = sizeof(void *);
4564                                 d->d_AlignMask = POINTER_ALIGN;
4565                                 if ((d->d_Scope.s_Flags & SCOPE_ALIGN) &&
4566                                     d->d_Scope.s_AlignOverride) {
4567                                         d->d_AlignMask =
4568                                                 d->d_Scope.s_AlignOverride - 1;
4569                                 }
4570                                 break;
4571                         case TY_PTRTO:
4572                         case TY_REFTO:
4573                                 if (d->d_ScopeFlags & SCOPE_LVALUE) {
4574                                         /*
4575                                          * NOTE: d->d_Bytes is different from
4576                                          *       the size of the underlying
4577                                          *       type that the LValueStor
4578                                          *       points to.
4579                                          */
4580                                         dassert(d->d_Op == DOP_ARGS_STORAGE);
4581                                         d->d_Bytes = sizeof(LValueStor);
4582                                         d->d_AlignMask = LVALUE_ALIGN;
4583                                 } else {
4584                                         d->d_Bytes = sizeof(PointerStor);
4585                                         d->d_AlignMask = POINTER_ALIGN;
4586                                 }
4587                                 if ((d->d_Scope.s_Flags & SCOPE_ALIGN) &&
4588                                     d->d_Scope.s_AlignOverride) {
4589                                         d->d_AlignMask =
4590                                                 d->d_Scope.s_AlignOverride - 1;
4591                                 }
4592                                 break;
4593                         default:
4594                                 resolveDecl(d, flags);
4595                                 break;
4596                         }
4597                         if (sg->sg_AlignMask < d->d_AlignMask)
4598                                 sg->sg_AlignMask = d->d_AlignMask;
4599                         sg->sg_Bytes = (sg->sg_Bytes + d->d_AlignMask) &
4600                                        ~d->d_AlignMask;
4601                         d->d_Offset = sg->sg_Bytes;
4602                         if (d->d_Op == DOP_ARGS_STORAGE) {
4603                                 if (d->d_ScopeFlags & SCOPE_UNLOCKED)
4604                                         d->d_Storage = GENSTAT_REFD;
4605                                 else if (d->d_ScopeFlags  & SCOPE_HARD)
4606                                         d->d_Storage = GENSTAT_LOCKH;
4607                                 else
4608                                         d->d_Storage = GENSTAT_LOCK;
4609                         } else {
4610                                 d->d_Storage = GENSTAT_REFD;
4611                         }
4612                         sg->sg_Bytes += d->d_Bytes;
4613                         if (d->d_StorDecl.ed_AssExp)
4614                                 sg->sg_Flags |= SGF_HASASS;
4615                         if (type->ty_Flags & TF_HASASS)
4616                                 sg->sg_Flags |= SGF_HASASS;
4617                         if (type->ty_Flags & TF_HASLVPTR)
4618                                 sg->sg_Flags |= SGF_HASLVPTR;
4619                         break;
4620                 case DOP_GLOBAL_STORAGE:
4621                         /* handled in pass2 */
4622                         break;
4623                 default:
4624                         dassert_semgrp(sg, 0);
4625                         break;
4626                 }
4627 #if 0
4628                 /*
4629                  * Rollup &obj into a SemGroup flag.
4630                  */
4631                 if (d->d_Flags & DF_ADDRUSED) {
4632                         sg->sg_Flags |= SGF_ADDRUSED;
4633                         fprintf(stderr, "RESOLVER ADDRUSED %s\n", d->d_Id);
4634                 }
4635 #endif
4636         }
4637
4638         /*
4639          * Final alignment
4640          */
4641         sg->sg_Bytes = (sg->sg_Bytes + sg->sg_AlignMask) & ~sg->sg_AlignMask;
4642         sg->sg_Flags |= SGF_RESOLVED;
4643         resolvePopSGDepend(dep);
4644
4645         return(1);
4646 }
4647
4648 /*
4649  * Followup - resolve globals
4650  */
4651 static
4652 int
4653 resolveSemGroup2(SemGroup *sg, int flags)
4654 {
4655         Declaration *d;
4656         Type *type;
4657
4658         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
4659
4660         if (sg->sg_Flags & SGF_GRESOLVED)
4661                 return(0);
4662         if (sg->sg_Flags & SGF_GRESOLVING) {
4663                 fprintf(stderr,
4664                         "Unable to resolve embedded recursive reference\n");
4665                 dassert_semgrp(sg, (sg->sg_Flags & SGF_GRESOLVING) == 0);
4666         }
4667         sg->sg_Flags |= SGF_GRESOLVING;
4668
4669         /*
4670          * First pass - resolve storage only.  Note that this specifically
4671          * does not try to handle the multiple semantic layers inside a
4672          * procedure.  See ResolveStorage() for that.
4673          */
4674         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
4675                 switch(d->d_Op) {
4676                 case DOP_CLASS:
4677                 case DOP_TYPEDEF:
4678                 case DOP_ALIAS:
4679                 case DOP_IMPORT:
4680                 case DOP_PROC:
4681                         break;
4682                 case DOP_STACK_STORAGE:
4683                         /*
4684                          * can't happen.  Stack storage is only used in
4685                          * executable contexts.
4686                          */
4687                         dassert_decl(d, 0);
4688                 case DOP_ARGS_STORAGE:
4689                 case DOP_GROUP_STORAGE:
4690                         /*
4691                          * Non-globals were handled in pass-1
4692                          */
4693                         break;
4694                 case DOP_GLOBAL_STORAGE:
4695                         /*
4696                          * Global storage must be handled in pass-2
4697                          */
4698                         type = d->d_StorDecl.ed_Type;
4699
4700                         switch(type->ty_Op) {
4701                         case TY_CPTRTO:
4702                                 d->d_Bytes = sizeof(void *);
4703                                 d->d_AlignMask = POINTER_ALIGN;
4704                                 if ((d->d_Scope.s_Flags & SCOPE_ALIGN) &&
4705                                     d->d_Scope.s_AlignOverride) {
4706                                         d->d_AlignMask =
4707                                                 d->d_Scope.s_AlignOverride - 1;
4708                                 }
4709                                 break;
4710                         case TY_PTRTO:
4711                         case TY_REFTO:
4712                                 d->d_Bytes = sizeof(PointerStor);
4713                                 d->d_AlignMask = POINTER_ALIGN;
4714                                 if ((d->d_Scope.s_Flags & SCOPE_ALIGN) &&
4715                                     d->d_Scope.s_AlignOverride) {
4716                                         d->d_AlignMask =
4717                                                 d->d_Scope.s_AlignOverride - 1;
4718                                 }
4719                                 break;
4720                         default:
4721                                 resolveDecl(d, flags);
4722                                 break;
4723                         }
4724                         if (sg->sg_GlobalAlignMask < d->d_AlignMask)
4725                                 sg->sg_GlobalAlignMask = d->d_AlignMask;
4726                         sg->sg_GlobalBytes = (sg->sg_GlobalBytes +
4727                                               d->d_AlignMask) & ~d->d_AlignMask;
4728                         d->d_Offset = sg->sg_GlobalBytes;
4729                         d->d_Storage = GENSTAT_REFD;
4730                         sg->sg_GlobalBytes += d->d_Bytes;
4731                         if (d->d_StorDecl.ed_AssExp)
4732                                 sg->sg_Flags |= SGF_GHASASS;
4733                         if (type->ty_Flags & TF_HASASS)
4734                                 sg->sg_Flags |= SGF_GHASASS;
4735                         if (type->ty_Flags & TF_HASLVPTR)
4736                                 sg->sg_Flags |= SGF_GHASLVPTR;
4737                         break;
4738                 default:
4739                         dassert_semgrp(sg, 0);
4740                         break;
4741                 }
4742         }
4743
4744         /*
4745          * Final alignment
4746          */
4747         sg->sg_GlobalBytes = (sg->sg_GlobalBytes + sg->sg_GlobalAlignMask) &
4748                              ~sg->sg_GlobalAlignMask;
4749         sg->sg_Flags |= SGF_GRESOLVED;
4750         return(1);
4751 }
4752
4753 static
4754 void
4755 resolveSemGroup3(SemGroup *sg, int flags)
4756 {
4757         Declaration *d;
4758         int dyncount;
4759
4760         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
4761
4762         /*
4763          * 0 - reserved for dynamic initialization
4764          * 1 - reserved for dynamic destructor
4765          */
4766         dyncount = 2;
4767
4768         /*
4769          * Third pass, resolve non-storage entities after setting
4770          * SGF_RESOLVED, these entities may legally embed this class (if
4771          * this is a class).
4772          *
4773          * Resolve pointers that were only partially resolved in the first
4774          * pass.
4775          *
4776          * Refinements have been resolved but we have to check them for
4777          * legality and set sg_Compat.
4778          *
4779          * Note that this is what allows us to typedef a subclass in its
4780          * superclass.  The typedef itself is safe.
4781          *
4782          * Also resolve storage pointer entities that were skipped in the
4783          * first pass.  Such pointers could point to ourselves.
4784          *
4785          * Finally, set SCOPE_UNLOCKED on any entity which does not
4786          * contain any lockable data (like int's).
4787          */
4788         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
4789                 /*
4790                  * Final resolution of refinements.
4791                  */
4792                 if (d->d_ScopeFlags & SCOPE_REFINE) {
4793                         resolveDecl(d->d_Super, flags);
4794                         resolveDecl(d, flags);
4795                         RefineDeclaration(sg, d->d_Super, d);
4796                 }
4797
4798                 /*
4799                  * Yada yada.
4800                  */
4801                 switch(d->d_Op) {
4802                 case DOP_CLASS:
4803                 case DOP_TYPEDEF:
4804                 case DOP_ALIAS:
4805                 case DOP_IMPORT:
4806                         resolveDecl(d, flags);
4807                         break;
4808                 case DOP_PROC:
4809                         resolveDecl(d, flags);
4810
4811                         /*
4812                          * For now internal generation does not need a
4813                          * dynamic component (and doesn't generate external
4814                          * code so the function wouldn't exist anyway).
4815                          */
4816                         if (d->d_ScopeFlags & SCOPE_INTERNAL)
4817                                 continue;
4818
4819                         /*
4820                          * Assign the dynamic index.  There may be multiple
4821                          * entries for the same d_Id, they are ordered such
4822                          * that refinements use the same DynIndex as in
4823                          * the superclass which is what allows dynamic method
4824                          * calls to work properly.  All non-refined subclass
4825                          * elements are ordered after all refined/non=refined
4826                          * superclass elements (replacing the superclass
4827                          * element and using the same DynIndex when refined).
4828                          */
4829                         d->d_DynIndex = dyncount;
4830                         ++dyncount;
4831                         break;
4832                 case DOP_ARGS_STORAGE:
4833                 case DOP_GROUP_STORAGE:
4834                 /*case DOP_STACK_STORAGE:*/
4835                 case DOP_GLOBAL_STORAGE:
4836                         switch(d->d_StorDecl.ed_Type->ty_Op) {
4837                         case TY_CPTRTO:
4838                         case TY_PTRTO:
4839                         case TY_REFTO:
4840                                 resolveDecl(d, flags);
4841                                 break;
4842                         }
4843                         break;
4844                 default:
4845                         dassert_semgrp(sg, 0);
4846                         break;
4847                 }
4848         }
4849
4850         /*
4851          * If no dynamic methods and no dynamic initialization or destruction
4852          * required, set dyncount to 0.
4853          */
4854         if (dyncount == 2 &&
4855             (sg->sg_Flags & SGF_HASASS) == 0 &&
4856             sg->sg_SRBase == NULL &&
4857             sg->sg_CBase == NULL &&
4858             sg->sg_DBase == NULL) {
4859                 dyncount = 0;
4860         }
4861         sg->sg_DynCount = dyncount;
4862         sg->sg_Flags &= ~SGF_RESOLVING;
4863 }
4864
4865 /*
4866  * findExpOper() -      Find operator declaration matching expression
4867  *
4868  *      Locate the operator declaration (a DOP_PROCDEF) that matches
4869  *      the expression or NULL if no match could be found.  The expression's
4870  *      left and right hand sides must already be resolved.
4871  *
4872  *      NOTE!  A temporary 'copy' Exp may be passed, not all fields are valid.
4873  */
4874 static Declaration *testIConstantForType(Declaration *d, Type *type, Exp *exp);
4875 static Declaration *testFConstantForType(Declaration *d, Type *type, Exp *exp);
4876
4877 static
4878 Declaration *
4879 findExpOper(Exp *exp, int flags)
4880 {
4881         Type *ltype;
4882         Type *rtype;
4883         Declaration *d;
4884
4885         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
4886
4887         if (exp->ex_Flags & EXF_BINARY) {
4888                 rtype = exp->ex_Rhs->ex_Type;
4889                 ltype = exp->ex_Lhs->ex_Type;
4890         } else {
4891                 dassert(exp->ex_Flags & EXF_UNARY);
4892                 rtype = NULL;
4893                 ltype = exp->ex_Lhs->ex_Type;
4894         }
4895
4896         /*
4897          * XXX look in our local semantic hierarchy for a compatible operator ?
4898          */
4899
4900         /*
4901          * Attempt to find a matching operator from the left hand side
4902          * type.
4903          */
4904         d = findOper(ltype, exp->ex_Id, ltype, rtype, flags);
4905
4906         if (d || (exp->ex_Flags & EXF_BINARY) == 0)
4907                 return(d);
4908
4909         /*
4910          * Attempt to find a matching binary operator from the right hand
4911          * side type.
4912          */
4913         d = findOper(rtype, exp->ex_Id, ltype, rtype, flags);
4914
4915         /*
4916          * If that fails but either the left or right-hand sides are
4917          * constants, see if we can find an operator by casting the
4918          * constant to the non-constant.
4919          */
4920         if (d == NULL) {
4921                 if (exp->ex_Rhs->ex_Token == TOK_INTEGER &&
4922                     exp->ex_Lhs->ex_Token != TOK_INTEGER &&
4923                     exp->ex_Lhs->ex_Token != TOK_FLOAT &&
4924                     (ltype->ty_Flags & TF_ISINTEGER)) {
4925                         d = findOper(ltype, exp->ex_Id, ltype, ltype, flags);
4926                         if (d)
4927                                 d = testIConstantForType(d, ltype, exp->ex_Rhs);
4928                 } else
4929                 if (exp->ex_Lhs->ex_Token == TOK_INTEGER &&
4930                     exp->ex_Rhs->ex_Token != TOK_INTEGER &&
4931                     exp->ex_Rhs->ex_Token != TOK_FLOAT &&
4932                     (rtype->ty_Flags & TF_ISINTEGER)) {
4933                         d = findOper(rtype, exp->ex_Id, rtype, rtype, flags);
4934                         if (d)
4935                                 d = testIConstantForType(d, rtype, exp->ex_Rhs);
4936                 } else
4937                 if (exp->ex_Rhs->ex_Token == TOK_FLOAT &&
4938                     exp->ex_Lhs->ex_Token != TOK_INTEGER &&
4939                     exp->ex_Lhs->ex_Token != TOK_FLOAT &&
4940                     (ltype->ty_Flags & TF_ISFLOATING)) {
4941                         d = findOper(ltype, exp->ex_Id, ltype, ltype, flags);
4942                         if (d)
4943                                 d = testFConstantForType(d, ltype, exp->ex_Rhs);
4944                 } else
4945                 if (exp->ex_Lhs->ex_Token == TOK_FLOAT &&
4946                     exp->ex_Rhs->ex_Token != TOK_INTEGER &&
4947                     exp->ex_Rhs->ex_Token != TOK_FLOAT &&
4948                     (rtype->ty_Flags & TF_ISFLOATING)) {
4949                         d = findOper(rtype, exp->ex_Id, rtype, rtype, flags);
4950                         if (d)
4951                                 d = testFConstantForType(d, rtype, exp->ex_Rhs);
4952                 }
4953         }
4954
4955         return(d);
4956 }
4957
4958 /*
4959  * Calculate whether the constant can be safely cast.  If it can,
4960  * cast the constant and return d.  Otherwise complain and return
4961  * NULL.
4962  */
4963 static
4964 Declaration *
4965 testIConstantForType(Declaration *d, Type *type, Exp *exp)
4966 {
4967         int64_t v = resolveGetConstExpInt64(exp);
4968
4969         if (type->ty_Flags & TF_ISUNSIGNED) {
4970                 switch(type->ty_Bytes) {
4971                 case 1:
4972                         if (v != (int64_t)(uint8_t)v)
4973                                 d = NULL;
4974                         break;
4975                 case 2:
4976                         if (v != (int64_t)(uint16_t)v)
4977                                 d = NULL;
4978                         break;
4979                 case 4:
4980                         if (v != (int64_t)(uint32_t)v)
4981                                 d = NULL;
4982                         break;
4983                 case 8:
4984                         break;
4985                 default:
4986                         break;
4987                 }
4988         } else {
4989                 switch(type->ty_Bytes) {
4990                 case 1:
4991                         if (v != (int64_t)(int8_t)v)
4992                                 d = NULL;
4993                         break;
4994                 case 2:
4995                         if (v != (int64_t)(int16_t)v)
4996                                 d = NULL;
4997                         break;
4998                 case 4:
4999                         if (v != (int64_t)(int32_t)v)
5000                                 d = NULL;
5001                         break;
5002                 case 8:
5003                         break;
5004                 default:
5005                         break;
5006                 }
5007         }
5008
5009         /*
5010          * If successful change the constant's type and reset the
5011          * interpreter to re-evaluate it.
5012          */
5013         if (d) {
5014                 exp->ex_Type = type;
5015                 exp->ex_Run = RunUnresolvedExp;
5016                 exp->ex_Run64 = Run64DefaultExp;
5017         } else {
5018                 ExpPrintError(exp, TOK_ERR_AUTOCAST_VALUE);
5019         }
5020         return d;
5021 }
5022
5023 static
5024 Declaration *
5025 testFConstantForType(Declaration *d, Type *type, Exp *exp)
5026 {
5027         float128_t v = resolveGetConstExpFloat128(exp);
5028
5029         switch(type->ty_Bytes) {
5030         case 4:
5031                 if (v != (float32_t)v)
5032                         d = NULL;
5033                 break;
5034         case 8:
5035                 if (v != (float64_t)v)
5036                         d = NULL;
5037                 break;
5038         case 16:
5039                 break;
5040         }
5041
5042         /*
5043          * If successful change the constant's type and reset the
5044          * interpreter to re-evaluate it.
5045          */
5046         if (d) {
5047                 exp->ex_Type = type;
5048                 exp->ex_Run = RunUnresolvedExp;
5049                 exp->ex_Run64 = Run64DefaultExp;
5050         } else {
5051                 ExpPrintError(exp, TOK_ERR_AUTOCAST_VALUE);
5052         }
5053         return d;
5054 }
5055
5056 static
5057 Declaration *
5058 findOper(Type *btype, string_t id, Type *ltype, Type *rtype, int flags)
5059 {
5060         SemGroup *sg;
5061         Declaration *d;
5062         int args = (rtype != NULL) ? 2 : 1;
5063
5064         flags &= ~RESOLVE_AUTOCAST;     /* not applicable to this function */
5065
5066         /*
5067          * Locate the base type.  If the base type does not have a SemGroup
5068          * there are no operators.  (XXX put system operators here)
5069          */
5070         sg = BaseType(&btype);
5071
5072         if (sg == NULL)
5073                 return(NULL);
5074
5075         /*
5076          * Look for the operator in the SemGroup
5077          */
5078         for (d = FindOperId(sg, id, args); d; d = d->d_ONext) {
5079                 resolveDecl(d, flags);
5080                 if (d->d_MyGroup == sg &&
5081                         d->d_Op == DOP_PROC &&
5082                         d->d_ProcDecl.ed_OperId == id &&
5083                         MatchOperatorTypes(d, ltype, rtype)
5084                 ) {
5085                         return(d);
5086                 }
5087         }
5088
5089         /*
5090          * Failed.  If the base type is a compound type, look for the
5091          * operator in the SemGroup for each element making up the compound
5092          * type.  e.g. so (mycustomtype, double) would find the operator
5093          * in mycustomtype.
5094          */
5095         if (btype->ty_Op == TY_COMPOUND) {
5096                 RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
5097                         Declaration *d2;
5098                         if (d->d_Op & DOPF_STORAGE) {
5099                                 d2 = findOper(d->d_StorDecl.ed_Type, id,
5100                                               ltype, rtype, flags);
5101                         } else if (d->d_Op == DOP_TYPEDEF) {
5102                                 d2 = findOper(d->d_TypedefDecl.ed_Type, id,
5103                                               ltype, rtype, flags);
5104                         } else {
5105                                 d2 = NULL;
5106                         }
5107                         if (d2)
5108                                 return(d2);
5109                 }
5110         }
5111         return(NULL);
5112 }
5113
5114 static void
5115 errorDottedId(string_t *ary, const char *ctl, ...)
5116 {
5117         va_list va;
5118         int i;
5119
5120         va_start(va, ctl);
5121         vfprintf(stderr, ctl, va);
5122         va_end(va);
5123         fprintf(stderr, ": %s", ary[0]);
5124         for (i = 1; ary[i]; ++i)
5125                 fprintf(stderr, ".%s", ary[i]);
5126         fprintf(stderr, "\n");
5127 }
5128
5129 /*
5130  * Resolve the alignment requirements for SemGroups related to
5131  * statements, including the alignment requirements needed for
5132  * temporary expression space.
5133  */
5134 void
5135 ResolveAlignment(Stmt *st, int flags)
5136 {
5137         SemGroup *sg = st->st_MyGroup;
5138         Stmt *scan;
5139
5140         if (st->st_Flags & STF_ALIGNRESOLVED)
5141                 return;
5142         st->st_Flags |= STF_ALIGNRESOLVED;
5143
5144         /*
5145          * If this is an executable semantic layer or an import layer then
5146          * assign storage to declarations up-front.  Of the various
5147          * DOP_*_STORAGE ops, we should only see DOP_STACK_STORAGE and
5148          * DOP_GLOBAL_STORAGE.
5149          *
5150          * Note: if this is the root ST_Import STF_SEMANTIC is *NOT* set and
5151          * sg will be NULL.
5152          */
5153         if ((st->st_Flags & STF_SEMANTIC) && st->st_Op != ST_Class) {
5154                 Declaration *d;
5155
5156                 /*
5157                  * Pre-scan for alignment.  Don't try to propagate the
5158                  * alignment to the parent for now as that would require
5159                  * recalculating the parent(s).
5160                  */
5161                 RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
5162                         switch(d->d_Op) {
5163                         case DOP_STACK_STORAGE:
5164                         case DOP_ARGS_STORAGE:
5165                         case DOP_GROUP_STORAGE:
5166                                 if (sg->sg_AlignMask < d->d_AlignMask)
5167                                         sg->sg_AlignMask = d->d_AlignMask;
5168                                 break;
5169                         case DOP_GLOBAL_STORAGE:
5170                                 if (sg->sg_GlobalAlignMask < d->d_AlignMask)
5171                                         sg->sg_GlobalAlignMask = d->d_AlignMask;
5172                                 break;
5173                         default:
5174                                 break;
5175                         }
5176                 }
5177         }
5178
5179         switch(st->st_Op) {
5180         case ST_Import:
5181                 break;
5182         case ST_Module:
5183         case ST_Class:
5184                 break;
5185         case ST_Typedef:
5186                 /* XXX needed? */
5187                 {
5188                         Declaration *d;
5189
5190                         d = st->st_TypedefStmt.es_Decl;
5191                         resolveStorageDeclExpAlign(d,
5192                                                    &sg->sg_TmpAlignMask,
5193                                                    flags);
5194                 }
5195                 break;
5196         case ST_Decl:
5197                 /*
5198                  * NOTE: Don't calculate for declarations that belong in
5199                  *       a different context.
5200                  */
5201                 {
5202                         Declaration *d;
5203                         int i;
5204
5205                         d = st->st_DeclStmt.es_Decl;
5206
5207                         for (i = 0; i < st->st_DeclStmt.es_DeclCount; ++i) {
5208                                 if (st->st_MyGroup == d->d_MyGroup)
5209                                         resolveStorageDeclExpAlign(d,
5210                                                         &sg->sg_TmpAlignMask,
5211                                                         flags);
5212                                 d = RUNE_NEXT(d, d_Node);
5213                         }
5214                 }
5215                 break;
5216         case ST_Block:
5217                 break;
5218         case ST_Proc:
5219                 break;
5220         case ST_Nop:
5221                 break;
5222         case ST_Loop:
5223                 {
5224                         if (st->st_LoopStmt.es_BCond) {
5225                                 resolveStorageExpAlign(st->st_LoopStmt.es_BCond,
5226                                                        &sg->sg_TmpAlignMask,
5227                                                        flags);
5228                         }
5229                         if (st->st_LoopStmt.es_ACond) {
5230                                 resolveStorageExpAlign(st->st_LoopStmt.es_ACond,
5231                                                        &sg->sg_TmpAlignMask,
5232                                                        flags);
5233                         }
5234                         if (st->st_LoopStmt.es_AExp) {
5235                                 resolveStorageExpAlign(st->st_LoopStmt.es_AExp,
5236                                                        &sg->sg_TmpAlignMask,
5237                                                        flags);
5238                         }
5239                 }
5240                 break;
5241         case ST_BreakCont:
5242                 break;
5243         case ST_Bad:
5244                 break;
5245         case ST_IfElse:
5246                 resolveStorageExpAlign(st->st_IfStmt.es_Exp,
5247                                        &sg->sg_TmpAlignMask,
5248                                        flags);
5249                 break;
5250         case ST_Return:
5251                 if (st->st_RetStmt.es_Exp)
5252                         resolveStorageExpAlign(st->st_RetStmt.es_Exp,
5253                                                &sg->sg_TmpAlignMask,
5254                                                flags);
5255                 break;
5256         case ST_Result:
5257                 if (st->st_ResStmt.es_Exp)
5258                         resolveStorageExpAlign(st->st_ResStmt.es_Exp,
5259                                                &sg->sg_TmpAlignMask,
5260                                                flags);
5261                 break;
5262         case ST_Switch:
5263                 /*
5264                  * The switch expression's temporary data must be saved while
5265                  * we are executing the sub-statements (the cases).
5266                  */
5267                 resolveStorageExpAlign(st->st_SwStmt.es_Exp,
5268                                        &sg->sg_TmpAlignMask,
5269                                        flags);
5270                 break;
5271         case ST_Case:
5272                 if (st->st_CaseStmt.es_Exp)
5273                         resolveStorageExpAlign(st->st_CaseStmt.es_Exp,
5274                                                &sg->sg_TmpAlignMask,
5275                                                flags);
5276                 break;
5277         case ST_Exp:
5278                 resolveStorageExpAlign(st->st_ExpStmt.es_Exp,
5279                                        &sg->sg_TmpAlignMask,
5280                                        flags);
5281                 break;
5282         case ST_ThreadSched:
5283                 break;
5284         default:
5285                 dassert_stmt(st, 0);
5286         }
5287
5288         /*
5289          * Calculate storage requirements for substatements.  offset
5290          * acts as our base.  We union the storage for the substatements
5291          * together.  Note that often scan->sg_MyGroup == sg.
5292          */
5293         RUNE_FOREACH(scan, &st->st_List, st_Node) {
5294                 if (scan->st_Op == ST_Class) {
5295                         ResolveAlignment(scan, flags);
5296                 } else if (scan->st_Op == ST_Decl &&
5297                            scan->st_DeclStmt.es_Decl->d_MyGroup !=
5298                            st->st_MyGroup) {
5299                         /*
5300                          * Do nothing
5301                          */
5302                         ;
5303                 } else if (scan->st_Op == ST_Decl &&
5304                            (scan->st_DeclStmt.es_Decl->d_Flags & DF_RESOLVED)) {
5305                         /*
5306                          * See prior comments, skip declarations that
5307                          * were moved to another context
5308                          *
5309                          * (already resolved so can use junk offsets)
5310                          */
5311                         resolveStorageDeclExpAlign(scan->st_DeclStmt.es_Decl,
5312                                                    &sg->sg_TmpAlignMask,
5313                                                    flags);
5314                 } else if (scan->st_Op == ST_Proc && 
5315                            scan->st_ProcStmt.es_Decl->d_ProcDecl.ed_OrigBody == scan
5316                 ) {
5317                         /* Do not resolve template procedures! */
5318                 } else if (scan->st_Flags & STF_SEMTOP) {
5319                         ResolveAlignment(scan, flags);
5320                 } else {
5321                         ResolveAlignment(scan, flags);
5322                 }
5323         }
5324
5325         /*
5326          * If this is a new semantic level call resolveStorageSemGroup() to
5327          * do the final cleanup of SemGroup issues.  This will redundantly
5328          * calculate temporary space requirements.  Also, due to type/class
5329          * references the temporary space for a class may have already been
5330          * resolved.  Since a class can only contain declarations it had
5331          * better match what we calculate here.
5332          *
5333          * Note that for non-Class executable SemGroup's TmpBytes is
5334          * incorporated in a downward fashion while sg_Bytes is incorporated
5335          * in an upward fashion.  It can become quite confusing.  Don't ask
5336          * me why I did it that way.
5337          */
5338         if (st->st_Flags & STF_SEMANTIC) {
5339                 if ((sg->sg_Flags & SGF_TMPRESOLVED) == 0) {
5340                         resolveStorageSemGroupAlign(sg, flags);
5341                 }
5342         }
5343
5344         /*
5345          * Propagate alignment requirements upward.
5346          */
5347         if ((st->st_Flags & (STF_SEMANTIC|STF_SEMTOP)) == STF_SEMANTIC) {
5348                 if (sg->sg_Parent->sg_AlignMask < sg->sg_AlignMask)
5349                         sg->sg_Parent->sg_AlignMask = sg->sg_AlignMask;
5350                 if (sg->sg_Parent->sg_TmpAlignMask < sg->sg_TmpAlignMask)
5351                         sg->sg_Parent->sg_TmpAlignMask = sg->sg_TmpAlignMask;
5352         }
5353 }
5354
5355 /*
5356  * ResolveStorage() -   Final storage resolution pass
5357  *
5358  *      This pass carefully scans the SemGroup hierarchy and assigns
5359  *      offsets to declarations.
5360  *
5361  *      PROCEDURES - all the various 'executable' semantic layers in
5362  *      a procedure are collapsed together for efficiency, so we only
5363  *      have to manage one context.  This means that the d_Offset 
5364  *      assigned to declarations in sub-blocks may exceed the sg_ size
5365  *      of the sub-block's SemGroup.  We do not attempt to resolve
5366  *      procedure body templates (d_ProcDecl.ed_OrigBody).
5367  *
5368  *      CLASSES - are given offsets in their SemGroup's relative to 0, if
5369  *                not already resolved.
5370  *
5371  *      IMPORTS - are given offsets in their SemGroup's relative to 0
5372  *
5373  *      COMPOUND TYPES - (such as procedure arguments) are given offsets
5374  *      in their SemGroup's relative to 0.
5375  *
5376  *      TEMPORARY STORAGE - expressions may require temporary storage
5377  *      for intermediate results.  That space is reserved here.
5378  *
5379  *      We specifically do not resolve unrelated storage.
5380  */
5381 static
5382 void
5383 ResolveStorage(Stmt *st, int flags)
5384 {
5385         runesize_t noffset;
5386         runesize_t offset;
5387         runesize_t goffset;
5388         runesize_t ngoffset;
5389         SemGroup *sg = st->st_MyGroup;
5390         Stmt *scan;
5391         Type *type;
5392
5393 #if 0
5394         if (st->st_Op != ST_Class) {
5395                 dassert((st->st_Flags & STF_RESOLVING) == 0);
5396                 if (st->st_Flags & STF_RESOLVED) {
5397                         return;
5398                 }
5399                 st->st_Flags |= STF_RESOLVING;
5400         }
5401 #endif
5402         dassert(st->st_Flags & STF_ALIGNRESOLVED);
5403         if (st->st_Flags & STF_TMPRESOLVED)
5404                 return;
5405         st->st_Flags |= STF_TMPRESOLVED;
5406
5407         /*
5408          * If this is an executable semantic layer or an import layer then
5409          * assign storage to declarations up-front.  Of the various
5410          * DOP_*_STORAGE ops, we should only see DOP_STACK_STORAGE and
5411          * DOP_GLOBAL_STORAGE.
5412          *
5413          * Note: if this is the root ST_Import STF_SEMANTIC is *NOT* set and
5414          * sg will be NULL.
5415          */
5416         if ((st->st_Flags & STF_SEMANTIC) && st->st_Op != ST_Class) {
5417                 Declaration *d;
5418
5419                 dassert((sg->sg_Flags & (SGF_FRESOLVED|SGF_FRESOLVING)) == 0);
5420
5421                 sg->sg_Flags |= SGF_FRESOLVING;
5422
5423                 /*
5424                  * The base offset for sub-semantic-blocks must match the
5425                  * alignment they require in order to allow us to do an
5426                  * aligned BZEROing of the space.  We do not include the
5427                  * temporary space here (it does not need to be BZERO'd).
5428                  *
5429                  * NOTE: sg_TmpAlignMask is taken into accoun when the
5430                  *       top-level frame is allocated.
5431                  */
5432                 if (st->st_Flags & STF_SEMTOP) {
5433                         dassert(sg->sg_Bytes == 0);
5434                         offset = 0;
5435                 } else {
5436                         offset = sg->sg_Parent->sg_Bytes;
5437                         offset = (offset + sg->sg_AlignMask) &
5438                                  ~sg->sg_AlignMask;
5439                 }
5440
5441                 sg->sg_BlkOffset = offset;
5442
5443                 RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
5444                         switch(d->d_Op) {
5445                         case DOP_STACK_STORAGE:
5446                         case DOP_ARGS_STORAGE:
5447                         case DOP_GROUP_STORAGE:
5448                                 type = d->d_StorDecl.ed_Type;
5449                                 offset = (offset + d->d_AlignMask) &
5450                                         ~d->d_AlignMask;
5451                                 dassert_decl(d, d->d_Offset == (runesize_t)-1);
5452                                 d->d_Offset = offset;
5453                                 if (d->d_Op == DOP_STACK_STORAGE ||
5454                                     d->d_Op == DOP_ARGS_STORAGE) {
5455                                         if (d->d_ScopeFlags & SCOPE_UNLOCKED)
5456                                                 d->d_Storage = GENSTAT_REFD;
5457                                         else if (d->d_ScopeFlags  & SCOPE_HARD)
5458                                                 d->d_Storage = GENSTAT_LOCKH;
5459                                         else
5460                                                 d->d_Storage = GENSTAT_LOCK;
5461                                 } else {
5462                                         d->d_Storage = GENSTAT_REFD;
5463                                 }
5464                                 offset += d->d_Bytes;
5465                                 if (d->d_StorDecl.ed_AssExp)
5466                                         sg->sg_Flags |= SGF_HASASS;
5467                                 if (type->ty_Flags & TF_HASASS)
5468                                         sg->sg_Flags |= SGF_HASASS;
5469                                 if (type->ty_Flags & TF_HASLVPTR)
5470                                         sg->sg_Flags |= SGF_HASLVPTR;
5471                                 break;
5472                         case DOP_GLOBAL_STORAGE:
5473                                 type = d->d_StorDecl.ed_Type;
5474                                 sg->sg_GlobalBytes =
5475                                         (sg->sg_GlobalBytes + d->d_AlignMask) &
5476                                         ~d->d_AlignMask;
5477                                 dassert_decl(d, d->d_Offset == (runesize_t)-1);
5478                                 d->d_Offset = sg->sg_GlobalBytes;
5479                                 d->d_Storage = GENSTAT_REFD;
5480                                 sg->sg_GlobalBytes += d->d_Bytes;
5481                                 if (d->d_StorDecl.ed_AssExp)
5482                                         sg->sg_Flags |= SGF_GHASASS;
5483                                 if (type->ty_Flags & TF_HASASS)
5484                                         sg->sg_Flags |= SGF_GHASASS;
5485                                 if (type->ty_Flags & TF_HASLVPTR)
5486                                         sg->sg_Flags |= SGF_GHASLVPTR;
5487                                 break;
5488                         default:
5489                                 break;
5490                         }
5491                 }
5492
5493                 /*
5494                  * The byte size of the block does not have to be aligned,
5495                  * but aligning it (within reason) might provide a benefit.
5496                  */
5497                 sg->sg_Bytes = offset;
5498
5499 #if 0
5500                 if (sg->sg_AlignMask < 256) {
5501                         sg->sg_Bytes = (offset + sg->sg_AlignMask) &
5502                                        ~sg->sg_AlignMask;
5503                 }
5504                 if (sg->sg_GlobalAlignMask < 256) {
5505                         sg->sg_GlobalBytes =
5506                                 (sg->sg_GlobalBytes + sg->sg_GlobalAlignMask) &
5507                                 ~sg->sg_GlobalAlignMask;
5508                 }
5509 #endif
5510                 sg->sg_BlkBytes = sg->sg_Bytes - sg->sg_BlkOffset;
5511                 sg->sg_Flags |= SGF_FRESOLVED;
5512                 sg->sg_Flags &= ~SGF_FRESOLVING;
5513         }
5514
5515         /*
5516          * Figure out how much temporary space we need to be able to execute
5517          * statements and expressions.  Temporary space, like the main
5518          * procedural space, must be inherited from and consolidated into
5519          * the top-level SemGroup
5520          */
5521         if (sg) {
5522                 offset = sg->sg_TmpBytes;
5523                 noffset = offset;
5524                 goffset = sg->sg_GlobalTmpBytes;
5525                 ngoffset = goffset;
5526         } else {
5527                 /*
5528                  * Root ST_Import.  avoid compiler warnings
5529                  */
5530                 offset = 0;
5531                 noffset = 0;
5532                 goffset = 0;
5533                 ngoffset = 0;
5534         }
5535
5536         switch(st->st_Op) {
5537         case ST_Import:
5538                 if (st->st_ImportStmt.es_DLL) {
5539                         void (*func)(void) = dlsym(st->st_ImportStmt.es_DLL,
5540                                                    "resolveStorage");
5541                         if (func)
5542                                 func();
5543                 }
5544                 break;
5545         case ST_Module:
5546         case ST_Class:
5547                 break;
5548         case ST_Typedef:
5549                 {
5550                         resolveStorageDeclExp(st->st_TypedefStmt.es_Decl,
5551                                               &noffset, &ngoffset);
5552                 }
5553                 break;
5554         case ST_Decl:
5555                 /*
5556                  * Temporary space for declarations are handled here.
5557                  *
5558                  * Resolve declarations, skipping any whos context was
5559                  * moved to a class (e.g. a declaration at the top level
5560                  * of a file like Fd.setfd(...) also exists in the Fd class).
5561                  */
5562                 {
5563                         Declaration *d;
5564                         int i;
5565
5566                         d = st->st_DeclStmt.es_Decl;
5567
5568                         if (d->d_Op == DOP_GLOBAL_STORAGE)
5569                                 st->st_DeclStmt.es_TmpOffset = goffset;
5570                         else
5571                                 st->st_DeclStmt.es_TmpOffset = offset;
5572                         printf("STDECLTMPOFFSET %zd\n", offset);
5573                         for (i = 0; i < st->st_DeclStmt.es_DeclCount; ++i) {
5574                                 runesize_t xoffset = offset;
5575                                 runesize_t xgoffset = goffset;
5576
5577 #if 1
5578                                 if (st->st_MyGroup != d->d_MyGroup) {
5579                                         /*printf("SKIPB %s\n", d->d_Id)*/;
5580                                         resolveStorageDeclExp(d, &xoffset, &xgoffset);
5581                                 } else if (d->d_Flags & DF_RESOLVED) {
5582                                         resolveStorageDeclExp(d, &xoffset, &xgoffset);
5583                                 }
5584 #endif
5585                                 else
5586                                         resolveStorageDeclExp(
5587                                                         d,
5588                                                         &xoffset,
5589                                                         &xgoffset);
5590
5591                                 if (noffset < xoffset)
5592                                         noffset = xoffset;
5593                                 if (ngoffset < xgoffset)
5594                                         ngoffset = xgoffset;
5595                                 d = RUNE_NEXT(d, d_Node);
5596                         }
5597                 }
5598                 break;
5599         case ST_Block:
5600                 break;
5601         case ST_Proc:
5602                 break;
5603         case ST_Nop:
5604                 break;
5605         case ST_Loop:
5606                 {
5607                         runesize_t xoffset;
5608
5609                         if (st->st_LoopStmt.es_BCond) {
5610                                 xoffset = offset;
5611                                 resolveStorageExp(st->st_LoopStmt.es_BCond,
5612                                                   &xoffset);
5613                                 if (noffset < xoffset)
5614                                         noffset = xoffset;
5615                         }
5616                         if (st->st_LoopStmt.es_ACond) {
5617                                 xoffset = offset;
5618                                 resolveStorageExp(st->st_LoopStmt.es_ACond,
5619                                                   &xoffset);
5620                                 if (noffset < xoffset)
5621                                         noffset = xoffset;
5622                         }
5623                         if (st->st_LoopStmt.es_AExp) {
5624                                 xoffset = offset;
5625                                 resolveStorageExp(st->st_LoopStmt.es_AExp,
5626                                                   &xoffset);
5627                                 if (noffset < xoffset)
5628                                         noffset = xoffset;
5629                         }
5630                 }
5631                 break;
5632         case ST_BreakCont:
5633                 break;
5634         case ST_Bad:
5635                 break;
5636         case ST_IfElse:
5637                 resolveStorageExp(st->st_IfStmt.es_Exp, &noffset);
5638                 break;
5639         case ST_Return:
5640                 if (st->st_RetStmt.es_Exp)
5641                         resolveStorageExp(st->st_RetStmt.es_Exp, &noffset);
5642                 break;
5643         case ST_Result:
5644                 if (st->st_ResStmt.es_Exp)
5645                         resolveStorageExp(st->st_ResStmt.es_Exp, &noffset);
5646                 break;
5647         case ST_Switch:
5648                 /*
5649                  * The switch expression's temporary data must be saved while
5650                  * we are executing the sub-statements (the cases).
5651                  */
5652                 resolveStorageExp(st->st_SwStmt.es_Exp, &noffset);
5653                 offset = noffset;
5654                 goffset = ngoffset;
5655                 break;
5656         case ST_Case:
5657                 if (st->st_CaseStmt.es_Exp)
5658                         resolveStorageExp(st->st_CaseStmt.es_Exp, &noffset);
5659                 break;
5660         case ST_Exp:
5661                 resolveStorageExp(st->st_ExpStmt.es_Exp, &noffset);
5662                 break;
5663         case ST_ThreadSched:
5664                 break;
5665         default:
5666                 dassert_stmt(st, 0);
5667         }
5668
5669         /*
5670          * Calculate storage requirements for substatements.  offset
5671          * acts as our base.  We union the storage for the substatements
5672          * together.  Note that often scan->sg_MyGroup == sg.
5673          */
5674         RUNE_FOREACH(scan, &st->st_List, st_Node) {
5675                 dassert(scan->st_Op != ST_Proc);
5676                 if (scan->st_Op == ST_Class) {
5677                         ResolveStorage(scan, flags);
5678 #if 1
5679                 } else if (scan->st_Op == ST_Decl &&
5680                            scan->st_DeclStmt.es_Decl->d_MyGroup !=
5681                            st->st_MyGroup) {
5682                         /*
5683                          * See prior comments, skip declarations that
5684                          * were moved to another context.
5685                          *
5686                          * (does not belong in context so can use
5687                          *  junk offsets).
5688                          */
5689                         runesize_t junk1 = 0;
5690                         runesize_t junk2 = 0;
5691                         /*
5692                         printf("SKIPC %s\n",
5693                                 scan->st_DeclStmt.es_Decl->d_Id);
5694                         */
5695                         resolveStorageDeclExp(scan->st_DeclStmt.es_Decl,
5696                                               &junk1, &junk2);
5697                 } else if (scan->st_Op == ST_Decl &&
5698                            (scan->st_DeclStmt.es_Decl->d_Flags & DF_RESOLVED)) {
5699                         /*
5700                          * See prior comments, skip declarations that
5701                          * were moved to another context
5702                          *
5703                          * (already resolved so can use junk offsets)
5704                          */
5705                         runesize_t junk1 = 0;
5706                         runesize_t junk2 = 0;
5707                         /*
5708                         printf("SKIPD %s\n",
5709                                 scan->st_DeclStmt.es_Decl->d_Id);
5710                         */
5711                         runesize_t save_offset;
5712                         runesize_t save_goffset;
5713                         save_offset = scan->st_MyGroup->sg_TmpBytes;
5714                         save_goffset = scan->st_MyGroup->sg_GlobalTmpBytes;
5715                         scan->st_MyGroup->sg_TmpBytes = offset;
5716                         scan->st_MyGroup->sg_GlobalTmpBytes = goffset;
5717                         resolveStorageDeclExp(scan->st_DeclStmt.es_Decl,
5718                                               &junk1, &junk2);
5719                         if (scan->st_MyGroup->sg_TmpBytes < save_offset)
5720                                 scan->st_MyGroup->sg_TmpBytes = save_offset;
5721                         if (scan->st_MyGroup->sg_GlobalTmpBytes < save_goffset) {
5722                                 scan->st_MyGroup->sg_GlobalTmpBytes = save_goffset;
5723                         }
5724                         if (noffset < scan->st_MyGroup->sg_TmpBytes)
5725                                 noffset = scan->st_MyGroup->sg_TmpBytes;
5726                         if (ngoffset < scan->st_MyGroup->sg_GlobalTmpBytes)
5727                                 ngoffset = scan->st_MyGroup->sg_GlobalTmpBytes;
5728 #endif
5729                 } else if (scan->st_Op == ST_Proc) {
5730                         /* Do not resolve template procedures! */
5731                         fprintf(stderr, "STORAGE %s\n", scan->st_ProcStmt.es_Decl->d_Id);
5732                         if (scan->st_ProcStmt.es_Decl->d_ProcDecl.ed_OrigBody == scan) {
5733                         } else {
5734                         }
5735                 } else if (scan->st_Flags & STF_SEMTOP) {
5736                         assert(scan->st_MyGroup != sg);
5737                         ResolveStorage(scan, flags);
5738                 } else {
5739                         /*
5740                          * This is a bit of a mess.  The baseline
5741                          * sg_TmpBytes needs to be set so calculated
5742                          * temporary offsets are relative to it, and
5743                          * then restored.  Otherwise we might blow
5744                          * away the SGF_TMPRESOLVED SemGroup
5745                          *
5746                          * XXX
5747                          */
5748                         runesize_t save_offset;
5749                         runesize_t save_goffset;
5750                         save_offset = scan->st_MyGroup->sg_TmpBytes;
5751                         save_goffset = scan->st_MyGroup->sg_GlobalTmpBytes;
5752                         scan->st_MyGroup->sg_TmpBytes = offset;
5753                         scan->st_MyGroup->sg_GlobalTmpBytes = goffset;
5754                         ResolveStorage(scan, flags);
5755
5756                         if (scan->st_MyGroup->sg_TmpBytes < save_offset)
5757                                 scan->st_MyGroup->sg_TmpBytes = save_offset;
5758                         if (scan->st_MyGroup->sg_GlobalTmpBytes < save_goffset) {
5759                                 scan->st_MyGroup->sg_GlobalTmpBytes = save_goffset;
5760                         }
5761                         if (noffset < scan->st_MyGroup->sg_TmpBytes)
5762                                 noffset = scan->st_MyGroup->sg_TmpBytes;
5763                         if (ngoffset < scan->st_MyGroup->sg_GlobalTmpBytes)
5764                                 ngoffset = scan->st_MyGroup->sg_GlobalTmpBytes;
5765                 }
5766         }
5767
5768         /*
5769          * If this is a new semantic level call resolveStorageSemGroup() to
5770          * do the final cleanup of SemGroup issues.  This will redundantly
5771          * calculate temporary space requirements.  Also, due to type/class
5772          * references the temporary space for a class may have already been
5773          * resolved.  Since a class can only contain declarations it had
5774          * better match what we calculate here.
5775          *
5776          * Note that for non-Class executable SemGroup's TmpBytes is
5777          * incorporated in a downward fashion while sg_Bytes is incorporated
5778          * in an upward fashion.  It can become quite confusing.  Don't ask
5779          * me why I did it that way.
5780          */
5781         if (st->st_Flags & STF_SEMANTIC) {
5782                 if ((sg->sg_Flags & SGF_TMPRESOLVED) == 0) {
5783                         resolveStorageSemGroup(sg, noffset, ngoffset);
5784                 } else {
5785                         dassert(sg->sg_TmpBytes == noffset && 
5786                                 sg->sg_GlobalTmpBytes == ngoffset);
5787                 }
5788         } else if (sg) {
5789                 sg->sg_TmpBytes = noffset;
5790                 sg->sg_GlobalTmpBytes = ngoffset;
5791         } /* else this is the Root st_Import */
5792
5793         if ((st->st_Flags & (STF_SEMANTIC|STF_SEMTOP)) == STF_SEMANTIC) {
5794                 sg->sg_Parent->sg_Bytes = sg->sg_Bytes;
5795         }
5796 }
5797
5798 /*
5799  * resolveStorageDeclExp() - resolve the storage reservation required to
5800  *                           process an expression.
5801  *
5802  *      This is an expression tree traversal storage resolution procedure.
5803  *      We have to traverse through declarations to get to default assignments
5804  *      and such.
5805  *
5806  *      If a declaration has no assigned default the underlying type may
5807  *      itself have an assigned default which must be dealt with.
5808  */
5809 static void
5810 resolveStorageDeclExpAlign(Declaration *d, runesize_t *expalignp, int flags)
5811 {
5812         switch(d->d_Op) {
5813         case DOP_CLASS:
5814                 /* recursion already dealt with */
5815                 break;
5816         case DOP_ARGS_STORAGE:
5817         case DOP_STACK_STORAGE:
5818         case DOP_GROUP_STORAGE:
5819                 {
5820                         Type *type = d->d_StorDecl.ed_Type;
5821
5822                         resolveStorageTypeExpAlign(type, expalignp, flags);
5823                         if (d->d_StorDecl.ed_AssExp) {
5824                                 resolveStorageExpAlign(d->d_StorDecl.ed_AssExp,
5825                                                        expalignp,
5826                                                        flags);
5827                         }
5828                 }
5829                 break;
5830         case DOP_GLOBAL_STORAGE:
5831                 {
5832                         Type *type = d->d_StorDecl.ed_Type;
5833
5834                         resolveStorageTypeExpAlign(type, expalignp, flags);
5835                         if (d->d_StorDecl.ed_AssExp) {
5836                                 resolveStorageExpAlign(d->d_StorDecl.ed_AssExp,
5837                                                        expalignp,
5838                                                        flags);
5839                         }
5840                 }
5841                 break;
5842         case DOP_ALIAS:
5843                 /*
5844                  * Never try to resolve storage considerations for an
5845                  * alias's assignment in the declaration itself.  The
5846                  * run-time context depends on who and how many other
5847                  * parts of the program reference the alias and the expression
5848                  * tree will be duplicated for each.
5849                  */
5850 #if 0
5851                 resolveStorageExpExp(d->d_AliasDecl.ed_AssExp, expalignp);
5852 #endif
5853                 break;
5854         case DOP_TYPEDEF:
5855                 /* XXX what about ty_AssExp ? should be in global space */
5856                 break;
5857         case DOP_IMPORT:
5858                 /* recursion already dealt with */
5859                 break;
5860         case DOP_PROC:
5861                 /*
5862                  * Resolution of procedure declarations might have been
5863                  * deferred (see TOK_ID in resolveExp()).
5864                  */
5865                 resolveDecl(d, 0);
5866                 {
5867                         Stmt *st;
5868
5869                         if ((st = d->d_ProcDecl.ed_ProcBody) != NULL) {
5870                                 ResolveAlignment(st, 0);
5871                         }
5872                 }
5873                 break;
5874         default:
5875                 dassert_decl(d, 0);
5876         }
5877 }
5878
5879 static void
5880 resolveStorageDeclExp(Declaration *d, runesize_t *offset, runesize_t *goffset)
5881 {
5882         switch(d->d_Op) {
5883         case DOP_CLASS:
5884                 /* recursion already dealt with */
5885                 break;
5886         case DOP_ARGS_STORAGE:
5887         case DOP_STACK_STORAGE:
5888         case DOP_GROUP_STORAGE:
5889                 {
5890                         Type *type = d->d_StorDecl.ed_Type;
5891                         runesize_t save_offset = *offset;
5892
5893                         resolveStorageType(type, &save_offset, 0);
5894                         if (d->d_StorDecl.ed_AssExp) {
5895                                 resolveStorageExp(d->d_StorDecl.ed_AssExp,
5896                                                   offset);
5897                         }
5898                         if (*offset < save_offset)
5899                                 *offset = save_offset;
5900                 }
5901                 break;
5902         case DOP_GLOBAL_STORAGE:
5903                 {
5904                         Type *type = d->d_StorDecl.ed_Type;
5905                         runesize_t save_offset = *goffset;
5906
5907                         resolveStorageType(type, &save_offset, 1);
5908                         if (d->d_StorDecl.ed_AssExp) {
5909                                 resolveStorageExp(d->d_StorDecl.ed_AssExp,
5910                                                   goffset);
5911                         }
5912                         if (*goffset < save_offset)
5913                                 *goffset = save_offset;
5914                 }
5915                 break;
5916         case DOP_ALIAS:
5917                 /*
5918                  * Never try to resolve storage considerations for an
5919                  * alias's assignment in the declaration itself.  The
5920                  * run-time context depends on who and how many other
5921                  * parts of the program reference the alias and the expression
5922                  * tree will be duplicated for each.
5923                  */
5924 #if 0
5925                 if (d->d_ScopeFlags & SCOPE_GLOBAL)
5926                         resolveStorageExp(d->d_AliasDecl.ed_AssExp, NULL, NULL);
5927                 else
5928                         resolveStorageExp(d->d_AliasDecl.ed_AssExp, NULL, NULL);
5929 #endif
5930                 break;
5931         case DOP_TYPEDEF:
5932                 /* XXX what about ty_AssExp ? should be in global space */
5933                 break;
5934         case DOP_IMPORT:
5935                 /* recursion already dealt with */
5936                 break;
5937         case DOP_PROC:
5938                 {
5939                         Stmt *st;
5940
5941                         if ((st = d->d_ProcDecl.ed_ProcBody) != NULL) {
5942                                 ResolveStorage(st, 0);
5943                         }
5944                 }
5945                 break;
5946         default:
5947                 dassert_decl(d, 0);
5948         }
5949 }
5950
5951 /*
5952  * resolveStorageExp() - resolve the temporary storage required to
5953  *                       support the expression, if any.
5954  *
5955  * We do not need to assign storage for expressions which return
5956  * lvalues, because they will simply return a pointer into
5957  * non-temporary storage.
5958  */
5959 static runesize_t
5960 resolveStorageExpOnly(Exp *exp, runesize_t *offset)
5961 {
5962         Type *type;
5963
5964         /*
5965          * Stop if the expression resolves to a type rather then a value,
5966          * e.g. when you do something like switch (typeof(int)) { ... }
5967          * Types are handled as thin pointers.
5968          */
5969         exp->ex_Flags |= EXF_TMPRESOLVED;
5970         if (exp->ex_Flags & EXF_RET_TYPE) {
5971                 *offset = (*offset + POINTER_ALIGN - 1) & ~(POINTER_ALIGN - 1);
5972                 exp->ex_TmpOffset = *offset;
5973                 *offset += sizeof(void *);
5974                 return(*offset);
5975
5976         }
5977
5978         /*
5979          * Assign temporary offset.  This offset does not overlap temporary
5980          * space reserved for sub-expressions.
5981          *
5982          * We must have an assigned type.  Expression sequences like:
5983          * 'module.blah' are collapsed into 'blah' long before we get
5984          * here, or they should be.  We should not encounter any
5985          * TOK_TCMV_ID expression tokens.  Structural id's (the right hand
5986          * side of X.Y) are resolved by their parent expression node and
5987          * no typing or temporary space is required.
5988          *
5989          * Expressions that return lvalues do not need temporary space.
5990          */
5991         type = exp->ex_Type;
5992         if (type == NULL) {
5993                 switch(exp->ex_Token) {
5994                 case TOK_STRUCT_ID:
5995                 case TOK_SEMGRP_ID:
5996                         break;
5997                 default:
5998                         printf("EXP %p %04x %p\n",
5999                                exp, exp->ex_Token, exp->ex_Decl);
6000                         dassert_exp(exp, 0);
6001                         break;
6002                 }
6003                 exp->ex_TmpOffset = -3;
6004         } else if (type->ty_SQFlags & SF_LVALUE) {
6005                 /*
6006                  * Expressive elements which return lvalues do not get
6007                  * temporary space.  Note that this also prevents lvalues
6008                  * such as large arrays (int ary[999999999]) from reserving
6009                  * unnecessary stack space.
6010                  *
6011                  * NOTE: SF_LVALUE is unrelated to SCOPE_LVALUE.  SCOPE_LVALUE
6012                  *       applies to SemGroup storage (LValueStor).  SF_LVALUE
6013                  *       merely flags the type for an expression as expecting
6014                  *       or not expecting an lvalue.
6015                  */
6016 #if 0
6017                 /*
6018                  * XXX removeme, LValueStor only applies to semgroups
6019                  */
6020                 runesize_t lvmask = sizeof(LValueStor) - 1;
6021                 *offset = (*offset + lvmask) & ~lvmask;
6022                 exp->ex_TmpOffset = *offset;
6023                 *offset = *offset + (lvmask + 1);
6024 #endif
6025                 exp->ex_TmpOffset = -2;
6026         } else {
6027                 /*
6028                  * Reserve temporary space for potential intermediate
6029                  * results.
6030                  *
6031                  * Compound expressions may need extra space to default-init
6032                  * the compound value, it is expected to be available to the
6033                  * generator right after the nominal type in the TmpOffset.
6034                  * XXX also make available to the interpreter?
6035                  *
6036                  * Procedure calls also may need extra space to default-init
6037                  * the return value.  XXX also make available to the
6038                  * interpreter?
6039                  */
6040                 *offset = (*offset + type->ty_AlignMask) & ~type->ty_AlignMask;
6041                 exp->ex_TmpOffset = *offset;
6042                 *offset = *offset + type->ty_Bytes;
6043                 if (exp->ex_Token == TOK_COMPOUND) {
6044                         /*
6045                          * NOTE: type might not yet be changed to compound,
6046                          *       but single-element compound will use the
6047                          *       same temporary space.
6048                          */
6049                         /**offset += type->ty_TmpBytes;*/
6050                         resolveStorageType(type, offset, 0);
6051                 } else if (exp->ex_Token == TOK_CALL) {
6052                         *offset += type->ty_TmpBytes;
6053                         resolveStorageType(type, offset, 0);
6054                 }
6055         }
6056         dassert(exp->ex_TmpOffset != -1);
6057         return (*offset);
6058 }
6059
6060 static void
6061 resolveStorageExpSub(Exp *exp, runesize_t *offset)
6062 {
6063 #if 0
6064         /*
6065          * Early term.  XXX don't do this.  For the moment we have an issue
6066          * with how typeof() processes temporary expression storage.  This
6067          * needs to be comprehensively fixed but it can be an issue if the
6068          * content is a dynamic type (via a ref or a var-args element)
6069          * so it is not trivial.
6070          */
6071         if (exp->ex_Flags & EXF_RET_TYPE)
6072                 return;
6073 #endif
6074         if (exp->ex_Type)
6075                 resolveStorageType(exp->ex_Type, offset, 0);
6076
6077         /*
6078          * Make sure resolved declarations have resolved temporary
6079          * storage for assigned expressions.  XXX
6080          */
6081         if (exp->ex_Token == TOK_ID || exp->ex_Token == TOK_CLASSID) {
6082                 Declaration *d;
6083
6084                 d = exp->ex_Decl;
6085                 if (d && (d->d_Flags & DF_RESOLVED)) {
6086                         resolveStorageDeclExp(d, offset, offset);
6087                 }
6088                 /* note: UNARY can be set for aliases */
6089         }
6090
6091         /*
6092          * Calculate the overlapping temporary space for sub-trees.
6093          */
6094         if (exp->ex_Flags & EXF_BINARY) {
6095                 /*
6096                  * Ensure lhs's NON-RECURSIVE temporary storage on-return
6097                  * does not intefere with rhs's, or vise-versa.
6098                  *
6099                  * To do this offset the rhs storage by the non-recursive
6100                  * lhs storage.
6101                  */
6102                 runesize_t xoffset;
6103                 runesize_t roffset;
6104
6105                 roffset = *offset;
6106                 xoffset = roffset;
6107                 resolveStorageExp(exp->ex_Lhs, &xoffset);
6108                 if (*offset < xoffset)
6109                         *offset = xoffset;
6110                 if (exp->ex_Lhs->ex_TmpOffset >= 0) {
6111                         xoffset = exp->ex_Lhs->ex_TmpOffset +
6112                                   exp->ex_Lhs->ex_Type->ty_Bytes;
6113                 } else {
6114                         xoffset = roffset;
6115                 }
6116                 resolveStorageExp(exp->ex_Rhs, &xoffset);
6117                 if (*offset < xoffset)
6118                         *offset = xoffset;
6119         } else if (exp->ex_Flags & EXF_UNARY) {
6120                 resolveStorageExp(exp->ex_Lhs, offset);
6121                 dassert_exp(exp, exp->ex_Lhs->ex_Next == NULL);
6122         } else if (exp->ex_Flags & EXF_COMPOUND) {
6123                 /*
6124                  * each element will be copied into the compound storage
6125                  * in turn, so we can union the temporary storage required
6126                  * for each element.
6127                  */
6128                 Exp *scan;
6129                 runesize_t noffset;
6130
6131                 noffset = *offset;
6132                 for (scan = exp->ex_Lhs; scan; scan = scan->ex_Next) {
6133                         runesize_t xoffset = *offset;
6134
6135                         dassert_exp(scan, scan->ex_Type != NULL);
6136
6137                         resolveStorageExp(scan, &xoffset);
6138                         if (noffset < xoffset)
6139                                 noffset = xoffset;
6140                 }
6141                 *offset = noffset;
6142         }
6143
6144 #if 0
6145         if (exp->ex_Token == TOK_CALL && exp->ex_Lhs->ex_Decl) {
6146                 Declaration *d = exp->ex_Lhs->ex_Decl;
6147                 fprintf(stderr, "FIXUP CALL %s type %p\n", d->d_Id, d->d_ProcDecl.ed_Type);
6148                 dassert(d->d_Op == DOP_PROC);
6149                 resolveStorageType(d->d_ProcDecl.ed_Type, offset, 0);
6150         }
6151 #endif
6152
6153 #if 0
6154         /* XXX what about alias assign-expressions */
6155         else if (exp->ex_Flags & EXF_ALIAS) {
6156 #if 0
6157                 dassert_decl(exp->ex_Decl,
6158                              (exp->ex_Decl->d_ScopeFlags & SCOPE_GLOBAL) == 0);
6159 #endif
6160                 resolveStorageExp(exp->ex_Decl->d_AliasDecl.ed_AssExp, offset);
6161         }
6162 #endif
6163 }
6164
6165 /*
6166  * [re]resolve temporary storage requirements.
6167  *
6168  * WARNING! This may be called more than once if an expression requires
6169  *          resolve-time interpretation to generate a constant.  In this
6170  *          ex_TmpOffset for the sub-chain may be regenerated from 0,
6171  *          and then just the top-level (post-constant-resolved)
6172  *          ex_TmpOffset will be restored by the caller.
6173  */
6174 static void
6175 resolveStorageExp(Exp *exp, runesize_t *offset)
6176 {
6177         runesize_t noffset;
6178         runesize_t xoffset;
6179
6180         xoffset = *offset;
6181         noffset = resolveStorageExpOnly(exp, &xoffset);
6182         xoffset = noffset;
6183         resolveStorageExpSub(exp, &xoffset);
6184         if (*offset < xoffset)
6185                 *offset = xoffset;
6186 }
6187
6188 static void
6189 resolveStorageExpAlign(Exp *exp, runesize_t *expalignp, int flags)
6190 {
6191         Type *type;
6192
6193         if (exp->ex_Flags & EXF_RET_TYPE) {
6194                 if (*expalignp < POINTER_ALIGN)
6195                         *expalignp = POINTER_ALIGN;
6196         }
6197 #if 0
6198         if (exp->ex_Decl) {
6199                 resolveDecl(exp->ex_Decl, 0);
6200         }
6201 #endif
6202
6203         type = exp->ex_Type;
6204         if (type == NULL) {
6205                 /*
6206                  * Do nothing
6207                  */
6208         } else {
6209                 if (type->ty_SQFlags & SF_LVALUE) {
6210                         if (*expalignp < POINTER_ALIGN)
6211                                 *expalignp = POINTER_ALIGN;
6212                 } else {
6213                         if (*expalignp < type->ty_AlignMask)
6214                                 *expalignp = type->ty_AlignMask;
6215                 }
6216                 resolveStorageTypeExpAlign(type, expalignp, flags);
6217         }
6218
6219         /*
6220          * This typically only occurs when the resolver needs to
6221          * evaluate a constant expression.  The declaration is
6222          * typically not resolved at that time.
6223          */
6224         if (exp->ex_Token == TOK_ID || exp->ex_Token == TOK_CLASSID) {
6225                 Declaration *d;
6226
6227                 d = exp->ex_Decl;
6228
6229                 if (d && ((flags & RESOLVE_CONSTEXP) || (d->d_Flags & DF_RESOLVED))) {
6230                         if (d && (d->d_Flags & DF_RESOLVED) == 0)
6231                                 resolveDecl(exp->ex_Decl, flags);
6232                         resolveStorageDeclExpAlign(d, expalignp, flags);
6233                 }
6234                 /* note: UNARY can be set for aliases */
6235         }
6236
6237         /*
6238          * Nominal code
6239          */
6240         if (exp->ex_Flags & EXF_BINARY) {
6241                 resolveStorageExpAlign(exp->ex_Lhs, expalignp, flags);
6242                 resolveStorageExpAlign(exp->ex_Rhs, expalignp, flags);
6243         } else if (exp->ex_Flags & EXF_UNARY) {
6244                 resolveStorageExpAlign(exp->ex_Lhs, expalignp, flags);
6245         } else if (exp->ex_Flags & EXF_COMPOUND) {
6246                 Exp *scan;
6247
6248                 for (scan = exp->ex_Lhs; scan; scan = scan->ex_Next) {
6249                         resolveStorageExpAlign(scan, expalignp, flags);
6250                 }
6251         }
6252 }
6253
6254 /*
6255  * resolveStorageType() - temporary space required to initialize type defaults
6256  *
6257  * Figure out the temporary space required to initialize a type's
6258  * defaults.  Note that the space will be figured independantly
6259  * for any SemGroup's.
6260  */
6261 static
6262 void
6263 resolveStorageTypeExpAlign(Type *type, runesize_t *expalignp, int flags)
6264 {
6265         SemGroup *sg = NULL;
6266         Type *subtype1 = NULL;
6267         Type *subtype2 = NULL;
6268
6269         if (type->ty_Flags & TF_ALIGNRESOLVED) {
6270                 if (*expalignp < type->ty_TmpAlignMask)
6271                         *expalignp = type->ty_TmpAlignMask;
6272                 return;
6273         }
6274         type->ty_Flags |= TF_ALIGNRESOLVED;
6275
6276         switch(type->ty_Op) {
6277         case TY_CLASS:
6278                 sg = type->ty_ClassType.et_SemGroup;
6279                 break;
6280         case TY_ARYOF:
6281                 subtype1 = type->ty_AryType.et_Type;
6282                 break;
6283         case TY_COMPOUND:
6284                 sg = type->ty_CompType.et_SemGroup;
6285                 break;
6286         case TY_PROC:
6287                 subtype1 = type->ty_ProcType.et_ArgsType;
6288                 subtype2 = type->ty_ProcType.et_RetType;
6289                 break;
6290         case TY_IMPORT:
6291                 sg = type->ty_ImportType.et_SemGroup;
6292                 break;
6293         case TY_ARGS:
6294                 sg = type->ty_ArgsType.et_SemGroup;
6295                 break;
6296         case TY_VAR:
6297                 sg = type->ty_VarType.et_SemGroup;
6298                 break;
6299         case TY_CPTRTO:
6300                 /* has nothing to do with initializing the pointer */
6301                 /* subtype1 = type->ty_CPtrType.et_Type; */
6302                 break;
6303         case TY_PTRTO:
6304                 /* has nothing to do with initializing the pointer */
6305                 /* subtype1 = type->ty_PtrType.et_Type; */
6306                 break;
6307         case TY_REFTO:
6308                 /* has nothing to do with initializing the pointer */
6309                 /* subtype1 = type->ty_RefType.et_Type; */
6310                 break;
6311         case TY_STORAGE:
6312         case TY_DYNAMIC:
6313                 /* 
6314                  * nothing to be done here.
6315                  */
6316                 break;
6317         case TY_UNRESOLVED: /* should be no unresolved types at this stage */
6318         default:
6319                 dassert_type(type, 0);
6320         }
6321
6322         if (subtype1) {
6323                 resolveStorageTypeExpAlign(subtype1,
6324                                            &subtype1->ty_TmpAlignMask,
6325                                            flags);
6326                 if (subtype1->ty_AssExp) {
6327                         resolveStorageExpAlign(subtype1->ty_AssExp,
6328                                                &subtype1->ty_TmpAlignMask,
6329                                                flags);
6330                 }
6331                 if (type->ty_TmpAlignMask < subtype1->ty_TmpAlignMask)
6332                         type->ty_TmpAlignMask = subtype1->ty_TmpAlignMask;
6333         }
6334         if (subtype2) {
6335                 resolveStorageTypeExpAlign(subtype2,
6336                                            &subtype2->ty_TmpAlignMask,
6337                                            flags);
6338                 if (subtype2->ty_AssExp) {
6339                         resolveStorageExpAlign(subtype2->ty_AssExp,
6340                                                &subtype2->ty_TmpAlignMask,
6341                                                flags);
6342                 }
6343                 if (type->ty_TmpAlignMask < subtype2->ty_TmpAlignMask)
6344                         type->ty_TmpAlignMask = subtype2->ty_TmpAlignMask;
6345         }
6346         if (type->ty_AssExp) {
6347                 resolveStorageExpAlign(type->ty_AssExp,
6348                                        &type->ty_TmpAlignMask,
6349                                        flags);
6350         }
6351         if (sg) {
6352                 if (resolveSemGroup1(sg, 0) && resolveSemGroup2(sg, 0))
6353                         resolveSemGroup3(sg, 0);
6354                 resolveStorageSemGroupAlign(sg, flags);
6355                 if (type->ty_TmpAlignMask < sg->sg_TmpAlignMask)
6356                         type->ty_TmpAlignMask = sg->sg_TmpAlignMask;
6357         }
6358         if (*expalignp < type->ty_TmpAlignMask)
6359                 *expalignp = type->ty_TmpAlignMask;
6360 }
6361
6362 static
6363 void
6364 resolveStorageType(Type *type, runesize_t *offset, int isglob)
6365 {
6366         SemGroup *sg = NULL;
6367         Type *subtype1 = NULL;
6368         Type *subtype2 = NULL;
6369         runesize_t save_offset1;
6370         runesize_t save_offset2;
6371         runesize_t save_offset3;
6372         runesize_t save_offsetx;
6373
6374         dassert(type->ty_Flags & TF_ALIGNRESOLVED);
6375         if (type->ty_Flags & TF_TMPRESOLVED) {
6376                 *offset += type->ty_TmpBytes;
6377                 return;
6378         }
6379         type->ty_Flags |= TF_TMPRESOLVED;
6380
6381         switch(type->ty_Op) {
6382         case TY_CLASS:
6383                 sg = type->ty_ClassType.et_SemGroup;
6384                 break;
6385         case TY_ARYOF:
6386                 subtype1 = type->ty_AryType.et_Type;
6387                 break;
6388         case TY_COMPOUND:
6389                 sg = type->ty_CompType.et_SemGroup;
6390                 break;
6391         case TY_PROC:
6392                 subtype1 = type->ty_ProcType.et_ArgsType;
6393                 subtype2 = type->ty_ProcType.et_RetType;
6394                 break;
6395         case TY_IMPORT:
6396                 sg = type->ty_ImportType.et_SemGroup;
6397                 break;
6398         case TY_ARGS:
6399                 sg = type->ty_ArgsType.et_SemGroup;
6400                 break;
6401         case TY_VAR:
6402                 sg = type->ty_VarType.et_SemGroup;
6403                 break;
6404         case TY_CPTRTO:
6405                 /* has nothing to do with initializing the pointer */
6406                 /* subtype1 = type->ty_CPtrType.et_Type; */
6407                 break;
6408         case TY_PTRTO:
6409                 /* has nothing to do with initializing the pointer */
6410                 /* subtype1 = type->ty_PtrType.et_Type; */
6411                 break;
6412         case TY_REFTO:
6413                 /* has nothing to do with initializing the pointer */
6414                 /* subtype1 = type->ty_RefType.et_Type; */
6415                 break;
6416         case TY_STORAGE:
6417         case TY_DYNAMIC:
6418                 /* 
6419                  * nothing to be done here.
6420                  */
6421                 break;
6422         case TY_UNRESOLVED: /* should be no unresolved types at this stage */
6423         default:
6424                 dassert_type(type, 0);
6425         }
6426
6427         save_offset1 = *offset;
6428         save_offset2 = *offset;
6429         save_offset3 = *offset;
6430         save_offsetx = *offset;
6431         if (subtype1) {
6432                 /*resolveType(subtype1, NULL, 0);*/
6433                 resolveStorageType(subtype1, &subtype1->ty_TmpBytes, 0);
6434                 if (subtype1->ty_AssExp) {
6435                         resolveStorageExp(subtype1->ty_AssExp,
6436                                           &subtype1->ty_TmpBytes);
6437                 }
6438                 save_offset1 += subtype1->ty_TmpBytes;
6439                 if (type->ty_TmpAlignMask < subtype1->ty_TmpAlignMask)
6440                         type->ty_TmpAlignMask = subtype1->ty_TmpAlignMask;
6441         }
6442         if (subtype2) {
6443                 /*resolveType(subtype2, NULL, 0);*/
6444                 resolveStorageType(subtype2, &subtype2->ty_TmpBytes, 0);
6445                 if (subtype2->ty_AssExp) {
6446                         resolveStorageExp(subtype2->ty_AssExp,
6447                                           &subtype2->ty_TmpBytes);
6448                 }
6449                 save_offset2 += subtype2->ty_TmpBytes;
6450                 if (type->ty_TmpAlignMask < subtype2->ty_TmpAlignMask)
6451                         type->ty_TmpAlignMask = subtype2->ty_TmpAlignMask;
6452         }
6453         if (type->ty_AssExp) {
6454                 resolveStorageExp(type->ty_AssExp, &type->ty_TmpBytes);
6455         }
6456         if (sg) {
6457                 if (resolveSemGroup1(sg, 0) && resolveSemGroup2(sg, 0))
6458                         resolveSemGroup3(sg, 0);
6459                 resolveStorageSemGroup(sg, 0, 0);
6460                 if (isglob) {
6461                         save_offset3 += sg->sg_GlobalTmpBytes;
6462                 } else {
6463                         save_offset3 += sg->sg_TmpBytes;
6464                 }
6465
6466                 /*
6467                  * Re-resolve the type flags.  XXX mostly fixed once I handled
6468                  * CBase/DBase/GBase in resolveSemGroup1().
6469                  */
6470                 if (sg->sg_Flags & SGF_HASASS)
6471                         type->ty_Flags |= TF_HASASS;
6472                 if (sg->sg_SRBase)
6473                         type->ty_Flags |= TF_HASLVPTR;
6474                 if (sg->sg_Flags & SGF_VARARGS)
6475                         type->ty_Flags |= TF_HASLVPTR;  /* XXX TF_VARARGS */
6476                 if (sg->sg_CBase)
6477                         type->ty_Flags |= TF_HASCONSTRUCT;
6478                 if (sg->sg_DBase)
6479                         type->ty_Flags |= TF_HASDESTRUCT;
6480
6481         }
6482         if (*offset < save_offset1)
6483                 *offset = save_offset1;
6484         if (*offset < save_offset2)
6485                 *offset = save_offset2;
6486         if (*offset < save_offset3)
6487                 *offset = save_offset3;
6488         type->ty_TmpBytes = *offset - save_offsetx;
6489 }
6490
6491 /*
6492  * This is used to resolve temporary storage requirements for
6493  * SemGroup's related to classes and compound types.  Temporary storage
6494  * requirements are calculated on a SemGroup-by-SemGroup basis and not
6495  * aggregated into any parent.
6496  *
6497  * In the final pass we also reverse the constructor and destructor lists
6498  * (sg_CBase and sg_DBase), and the pointer/lvalue list (SRBase).  These
6499  * lists were originally constructed by prepending and are thus in the
6500  * wrong order.
6501  */
6502 static
6503 void
6504 resolveStorageSemGroupAlign(SemGroup *sg, int flags)
6505 {
6506         Declaration *d;
6507
6508         if (sg->sg_Flags & SGF_ALIGNRESOLVED)
6509                 return;
6510         sg->sg_Flags |= SGF_ALIGNRESOLVED;
6511
6512         /*
6513          * SGF_RESOLVED might not be set.  This can only happen because we
6514          * allow individual declarations in global SemGroups to be resolved
6515          * without having to resolve the whole group.  This allows unused
6516          * declarations to be omitted by the code generator.
6517          */
6518         if ((sg->sg_Flags & SGF_RESOLVED) == 0)
6519                 sg->sg_Flags |= SGF_RESOLVED;
6520
6521         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
6522                 resolveStorageDeclExpAlign(d, &sg->sg_TmpAlignMask, flags);
6523                 if (d->d_ScopeFlags & SCOPE_GLOBAL) {
6524                         if (sg->sg_GlobalAlignMask < d->d_AlignMask)
6525                                 sg->sg_GlobalAlignMask = d->d_AlignMask;
6526                 } else {
6527                         if (sg->sg_AlignMask < d->d_AlignMask)
6528                                 sg->sg_AlignMask = d->d_AlignMask;
6529                 }
6530         }
6531 }
6532
6533 static
6534 void
6535 resolveStorageSemGroup(SemGroup *sg, runesize_t noffset, runesize_t ngoffset)
6536 {
6537         Declaration *d;
6538         Declaration *d2;
6539
6540 #if 0
6541         if ((sg->sg_Flags & SGF_RESOLVED) == 0) {
6542                 if (resolveSemGroup1(sg, 0) && resolveSemGroup2(sg, 0))
6543                         resolveSemGroup3(sg, 0);
6544         }
6545 #endif
6546         dassert(sg->sg_Flags & SGF_ALIGNRESOLVED);
6547         if (sg->sg_Flags & SGF_TMPRESOLVED)
6548                 return;
6549         sg->sg_Flags |= SGF_TMPRESOLVED;
6550
6551         /*
6552          * Final pass
6553          */
6554         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
6555                 runesize_t offset = 0;
6556                 runesize_t goffset = 0;
6557
6558                 resolveStorageDeclExp(d, &offset, &goffset);
6559                 if (noffset < offset)
6560                         noffset = offset;
6561                 if (ngoffset < goffset)
6562                         ngoffset = goffset;
6563         }
6564
6565         /*
6566          * Reverse order
6567          */
6568         if ((d2 = sg->sg_CBase) != NULL) {
6569                 sg->sg_CBase = NULL;
6570                 while ((d = d2) != NULL) {
6571                         d2 = d->d_CNext;
6572                         d->d_CNext = sg->sg_CBase;
6573                         sg->sg_CBase = d;
6574                 }
6575         }
6576         if ((d2 = sg->sg_DBase) != NULL) {
6577                 sg->sg_DBase = NULL;
6578                 while ((d = d2) != NULL) {
6579                         d2 = d->d_DNext;
6580                         d->d_DNext = sg->sg_DBase;
6581                         sg->sg_DBase = d;
6582                 }
6583         }
6584         if ((d2 = sg->sg_GBase) != NULL) {
6585                 sg->sg_GBase = NULL;
6586                 while ((d = d2) != NULL) {
6587                         d2 = d->d_GNext;
6588                         d->d_GNext = sg->sg_GBase;
6589                         sg->sg_GBase = d;
6590                 }
6591         }
6592         if ((d2 = sg->sg_SRBase) != NULL) {
6593                 sg->sg_SRBase = NULL;
6594                 while ((d = d2) != NULL) {
6595                         d2 = d->d_SRNext;
6596                         d->d_SRNext = sg->sg_SRBase;
6597                         sg->sg_SRBase = d;
6598                 }
6599         }
6600         sg->sg_TmpBytes = noffset;
6601         sg->sg_GlobalTmpBytes = ngoffset;
6602 }
6603
6604 /*
6605  * Return non-zero if the method procedure wants the 'this' variable
6606  * to be an lvalue-pointer rather than an lvalue-target-object.  In this
6607  * situation we do not want to indirect the pointer.
6608  */
6609 static
6610 int
6611 methodProcThisIsPointer(Type *type)
6612 {
6613         Declaration *d;
6614         SemGroup *sg;
6615         int r;
6616
6617         dassert(type->ty_Op == TY_PROC);
6618         dassert(type->ty_ProcType.et_ArgsType->ty_Op == TY_ARGS);
6619         sg = type->ty_ProcType.et_ArgsType->ty_CompType.et_SemGroup;
6620         d = RUNE_FIRST(&sg->sg_DeclList);
6621         dassert(d->d_Id == String_This);
6622         switch (d->d_StorDecl.ed_Type->ty_Op) {
6623         case TY_REFTO:
6624                 r = 1;
6625                 break;
6626         case TY_PTRTO:
6627                 r = 1;
6628                 break;
6629         case TY_CPTRTO:
6630                 fprintf(stderr,
6631                         "methodProcThisIsPointer(): method call through "
6632                         "C pointer is illegal\n");
6633                 dassert_decl(d, 0);
6634                 r = 1;
6635                 break;
6636         default:
6637                 r = 0;
6638                 break;
6639         }
6640         return r;
6641 }
6642
6643 /*
6644  * Calculate SG dependencies
6645  */
6646 #define SGDEP_HSIZE     1024
6647 #define SGDEP_HMASK     (SGDEP_HSIZE - 1)
6648
6649 static SGDepend *SGDepHash[SGDEP_HSIZE];
6650 static SemGroup *SGCurrentDep;
6651
6652 static
6653 SGDepend **
6654 resolveSGDependHash(SemGroup *src, SemGroup *dst)
6655 {
6656         intptr_t hv;
6657
6658         hv = ((intptr_t)src >> 7) ^ ((intptr_t)dst >> 5);
6659         hv ^= hv >> 16;
6660         return (&SGDepHash[hv & SGDEP_HMASK]);
6661 }
6662
6663 static
6664 SemGroup *
6665 resolvePushSGDepend(SemGroup *sg)
6666 {
6667         SemGroup *last;
6668         SGDepend *dep;
6669         SGDepend **depp;
6670
6671         depp = resolveSGDependHash(SGCurrentDep, sg);
6672         for (dep = *depp; dep; dep = dep->hnext) {
6673                 if (dep->src == SGCurrentDep && dep->dst == sg)
6674                         break;
6675         }
6676         if (dep == NULL) {
6677                 dep = zalloc(sizeof(SGDepend));
6678                 dep->hnext = *depp;
6679                 dep->src = SGCurrentDep;
6680                 dep->dst = sg;
6681                 *depp = dep;
6682                 if (SGCurrentDep) {
6683                         dep->next = SGCurrentDep->sg_DepFirst;
6684                         SGCurrentDep->sg_DepFirst = dep;
6685                 }
6686         }
6687         last = SGCurrentDep;
6688         SGCurrentDep = sg;
6689
6690         return last;
6691 }
6692
6693 static
6694 void
6695 resolvePopSGDepend(SemGroup *dep)
6696 {
6697         SGCurrentDep = dep;
6698 }