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