]> andersk Git - splint.git/blob - src/transferChecks.c
bc4c8c959d5b6a78919cc341ff810e838ac8c978
[splint.git] / src / transferChecks.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 ** 
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 ** 
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** transferChecks.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30 # include "transferChecks.h"
31
32 /* transfer types: */
33 typedef enum
34 {
35   TT_FCNRETURN,
36   TT_DOASSIGN,
37   TT_FIELDASSIGN,
38   TT_FCNPASS,
39   TT_GLOBPASS,
40   TT_GLOBRETURN,
41   TT_PARAMRETURN,
42   TT_LEAVETRANS,
43   TT_GLOBINIT
44 } transferKind;
45
46 static void checkStructTransfer (exprNode p_lhs, sRef p_slhs, exprNode p_rhs, sRef p_srhs,
47                                  fileloc p_loc, transferKind p_tt);
48 static void checkMetaStateConsistent (/*@exposed@*/ sRef p_fref, sRef p_tref, 
49                                       fileloc p_loc, transferKind p_transferType) ;
50
51 static void checkLeaveTrans (uentry p_actual, transferKind p_transferType);
52 static void checkTransfer (exprNode p_fexp, /*@dependent@*/ sRef p_fref,
53                            exprNode p_texp, /*@dependent@*/ sRef p_tref, 
54                            exprNode p_fcn, /* for printing better error messages */
55                            fileloc p_loc, transferKind p_transferType);
56 static void checkGlobTrans (uentry p_glob, transferKind p_type);
57
58 static ynm
59 checkCompletelyDefined (exprNode p_fexp, /*@exposed@*/ sRef p_fref, sRef p_ofref,
60                         exprNode p_texp, sRef p_tref,
61                         bool p_topLevel, bool p_inUnion, bool p_directUnion,
62                         fileloc p_loc, transferKind p_transferType, int p_depth,
63                         bool p_report);
64
65 static /*@exposed@*/ sRef dependentReference (sRef p_sr);
66 static bool canLoseLocalReference (/*@dependent@*/ sRef p_sr, fileloc p_loc) ;
67
68 /*
69 ** returns the most specific alkind
70 */
71
72 alkind alkind_resolve (alkind a1, alkind a2)
73 {
74   if (a1 == AK_UNKNOWN || a1 == AK_ERROR) return a2;
75   if (a2 == AK_UNKNOWN || a2 == AK_ERROR || a2 == AK_LOCAL) return a1;
76   if (a1 == AK_LOCAL) return a2;
77   return a1;
78 }
79
80 /*
81 ** tref <- fref
82 **
83 ** transferType:
84 **   FCNRETURN   return fref; tref is return type
85 **   GLOBASSIGN  tref = fref; 
86 **   FCNPASS     call (fref) ; tref is the argument type
87 **
88 */
89
90 static /*@only@*/ cstring
91 transferErrorMessage (transferKind transferType, alkind tkind) /*@*/ 
92 {
93   switch (transferType)
94     {
95     case TT_FCNRETURN:
96       return (message ("returned as %s", alkind_unparse (tkind)));
97     case TT_DOASSIGN:
98       return (message ("assigned to %s", alkind_unparse (tkind)));
99     case TT_FIELDASSIGN:
100       return (message ("assigned to %s", alkind_unparse (tkind)));
101     case TT_GLOBINIT:
102       return (message ("used as initial value for %s", 
103                        alkind_unparse (tkind)));
104     case TT_FCNPASS:
105       return (message ("passed as %s param", alkind_unparse (tkind)));
106     BADDEFAULT;
107     }
108   BADEXIT;
109 }
110
111 static /*@only@*/ cstring
112 transferErrorExcerpt (transferKind transferType, exprNode fexp, exprNode texp, exprNode fcn) /*@*/ 
113 {
114   switch (transferType)
115     {
116     case TT_FCNRETURN:
117       return (message ("return %s", exprNode_unparse (fexp)));
118     case TT_FIELDASSIGN:
119     case TT_DOASSIGN:
120     case TT_GLOBINIT:
121       return (message ("%s = %s", exprNode_unparse (texp), exprNode_unparse (fexp)));
122     case TT_FCNPASS:
123       if (exprNode_isDefined (fcn))
124         {
125           return message ("%s(..., %s, ...)",
126                           exprNode_unparse (fcn),
127                           exprNode_unparse (fexp));
128         }
129       else
130         {
131           return cstring_copy (exprNode_unparse (fexp));  
132         }
133     BADDEFAULT;
134     }
135   BADEXIT;
136 }
137
138 static cstring
139 transferErrorExpMessage (transferKind transferType, exkind tkind) /*@*/
140 {
141   if (exkind_isUnknown (tkind))
142     {
143       switch (transferType)
144         {
145         case TT_FCNRETURN:
146           return (cstring_makeLiteral ("returned without qualification"));
147         case TT_FIELDASSIGN:
148         case TT_DOASSIGN:
149           return (cstring_makeLiteral ("assigned to unqualified reference"));
150         case TT_FCNPASS:
151           return (cstring_makeLiteral ("passed without qualification"));
152         case TT_GLOBINIT:
153           return (cstring_makeLiteral ("used as initial value for unqualified storage"));
154         BADDEFAULT;
155         }
156     }
157   else
158     {
159       switch (transferType)
160         {
161         case TT_FCNRETURN:
162           return (message ("returned as %s", exkind_unparse (tkind)));
163         case TT_FIELDASSIGN:
164         case TT_DOASSIGN:
165           return (message ("assigned to %s", exkind_unparse (tkind)));
166         case TT_FCNPASS:
167           return (message ("passed as %s param", exkind_unparse (tkind)));
168           BADDEFAULT;
169         }
170     }
171
172   BADEXIT;
173 }
174
175 static /*@observer@*/ cstring
176 transferNullMessage (transferKind transferType) /*@*/
177 {
178   switch (transferType)
179     {
180     case TT_FCNRETURN:
181       return (cstring_makeLiteralTemp ("returned as non-null"));
182     case TT_DOASSIGN:
183     case TT_FIELDASSIGN:
184       return (cstring_makeLiteralTemp ("assigned to non-null"));
185     case TT_GLOBINIT:
186       return (cstring_makeLiteralTemp ("initialized to non-null"));
187     case TT_FCNPASS:
188       return (cstring_makeLiteralTemp ("passed as non-null param"));
189     BADDEFAULT;
190     }
191   BADEXIT;
192 }
193
194 static /*@dependent@*/ exprNode atFunction = exprNode_undefined;
195 static int atArgNo = 0;
196 static int atNumArgs = 0;
197
198 static cstring generateText (exprNode e1, exprNode e2, 
199                              sRef tref, transferKind tt) 
200    /*@*/
201 {
202   if (tt == TT_DOASSIGN || tt == TT_GLOBINIT)
203     {
204       return (message ("%s = %s", exprNode_unparse (e2),
205                        exprNode_unparse (e1)));
206     }
207   else if (tt == TT_FIELDASSIGN)
208     {
209       return (message ("%s = %s (field %q)",
210                        exprNode_unparse (e2),
211                        exprNode_unparse (e1),
212                        sRef_unparse (tref)));
213     }
214   else if (tt == TT_FCNPASS)
215     {
216       return (message ("%s (%s%s%s)",
217                        exprNode_unparse (atFunction),
218                        (atArgNo == 1 ? cstring_undefined 
219                 : cstring_makeLiteralTemp ("..., ")),
220                        exprNode_unparse (e1),
221                        (atArgNo == atNumArgs ? cstring_undefined
222                         : cstring_makeLiteralTemp (", ..."))));
223     }
224   else
225     {
226       return (cstring_copy (exprNode_unparse (e1)));
227     }
228 }
229
230 static /*@observer@*/ cstring
231 transferType_unparse (transferKind transferType) /*@*/
232 {
233   switch (transferType)
234     {
235     case TT_FCNRETURN:
236       return (cstring_makeLiteralTemp ("Returned"));
237     case TT_DOASSIGN:
238     case TT_FIELDASSIGN:
239       return (cstring_makeLiteralTemp ("Assigned"));
240     case TT_FCNPASS:
241       return (cstring_makeLiteralTemp ("Passed"));
242     case TT_GLOBINIT:
243       return (cstring_makeLiteralTemp ("Initialized"));
244     case TT_GLOBRETURN:
245       return (cstring_makeLiteralTemp ("GLOB RETURN!"));
246     case TT_GLOBPASS:
247       return (cstring_makeLiteralTemp ("GLOB PASS!"));
248     case TT_PARAMRETURN:
249       return (cstring_makeLiteralTemp ("PARAM RETURN!"));
250     case TT_LEAVETRANS:
251       return (cstring_makeLiteralTemp ("LEAVE TRANS!"));
252     BADDEFAULT;
253     }
254   BADEXIT;
255 }
256
257 static /*@observer@*/ cstring udError (sRef s)
258 {
259   if (sRef_isDead (s))
260     {
261       return cstring_makeLiteralTemp ("released");
262     }
263   else if (sRef_isAllocated (s))
264     {
265       return cstring_makeLiteralTemp ("allocated but not defined");
266     }
267   else
268     {
269       return cstring_makeLiteralTemp ("undefined");
270     }
271 }
272
273 static /*@only@*/ 
274 cstring defExpl (sRef s) /*@*/
275 {
276   sRef rb = sRef_getRootBase (s);
277
278   if (sRef_sameName (rb, s))
279     {
280       if (sRef_isAllocated (s))
281         {
282           return cstring_makeLiteral (" (allocated only)");
283         }
284       return cstring_undefined;
285     }
286   else
287     {
288       return (message (" (%q is %s)", sRef_unparse (s), udError (s)));
289     }
290 }
291
292 /*
293 **
294 ** More than just definition checking --- checks for consistent state also!
295 **
296 ** Returns TRUE if fref is completely defined.
297 ** if !report, returns TRUE unless error is at the deep level.
298 */
299
300 static ynm
301 checkCompletelyDefined (exprNode fexp, /*@exposed@*/ sRef fref, sRef ofref,
302                         exprNode texp, sRef tref, 
303                         bool topLevel, bool inUnion, bool directUnion,
304                         fileloc loc, transferKind transferType,
305                         int depth, bool report)
306 {
307   ctype ct;
308   alkind fkind = sRef_getAliasKind (fref);
309   alkind tkind = sRef_getAliasKind (tref);
310   
311   DPRINTF (("Check completely defined: %s [%s] / %s [%s]",
312             exprNode_unparse (fexp), sRef_unparseFull (fref),
313             exprNode_unparse (texp), sRef_unparseFull (tref)));
314
315   if (depth > MAXDEPTH)
316     {
317       llquietbug
318         (message 
319          ("Check definition limit exceeded, checking %q. "
320           "This either means there is a variable with at least "
321           "%d indirections apparent in the program text, or "
322           "there is a bug in Splint.",
323           sRef_unparse (fref),
324           MAXDEPTH));
325
326       return YES;
327     }
328
329   if (!sRef_isKnown (fref))
330     {
331       return YES;
332     }
333
334   if (sRef_isDead (fref))
335     {
336       DPRINTF (("Dead storage to completely defined: %s", sRef_unparseFull (fref)));
337     }
338
339   if (alkind_isStack (fkind))
340     {
341       ctype rt = ctype_realType (sRef_getType (tref));
342
343       if (ctype_isMutable (rt) && !ctype_isSU (rt))
344         {
345           if (transferType == TT_PARAMRETURN)
346             {
347               if (optgenerror 
348                   (FLG_RETSTACK,
349                    message
350                    ("Stack-allocated storage %qreachable from parameter %q",
351                     sRef_unparseOpt (fref),
352                     sRef_unparse (ofref)),
353                    loc))
354                 {
355                   sRef_showAliasInfo (fref);
356                 }
357             }
358           else if (transferType == TT_GLOBRETURN)
359             {
360               if (optgenerror 
361                   (FLG_RETSTACK,
362                    message
363                    ("Stack-allocated storage %qreachable from global %q",
364                     sRef_unparseOpt (fref),
365                     sRef_unparse (ofref)),
366                    loc))
367                 {
368                   sRef_showAliasInfo (fref);
369                 }
370             }
371           else if (transferType == TT_FCNRETURN)
372             {
373               if (optgenerror 
374                   (FLG_RETSTACK,
375                    message 
376                    ("Stack-allocated storage %qreachable from return value: %s",
377                     sRef_unparseOpt (fref), 
378                     exprNode_unparse (fexp)),
379                    loc))
380                 {
381                   sRef_showAliasInfo (fref);
382                 }
383             }
384           else
385             {
386               /* no error */
387             }
388         }
389     }
390
391   if (!topLevel)
392     {
393       DPRINTF (("From: %s ==> %s",
394                 sRef_unparseFull (fref),
395                 sRef_unparseFull (tref)));
396       
397       checkMetaStateConsistent (fref, tref, loc, transferType);
398
399       if ((sRef_isObserver (fref) && !sRef_isObserver (tref))
400           || (sRef_isExposed (fref) && !(sRef_isObserver (tref) 
401                                          || sRef_isExposed (tref))))
402         {
403           flagcode code = (sRef_isObserver (fref) 
404                            ? FLG_OBSERVERTRANS : FLG_EXPOSETRANS);
405
406           if (!sRef_isStateLive (fref))
407             {
408               ; /* no error (will be a definition error) */
409             }
410           else if (transferType == TT_DOASSIGN
411                    || transferType == TT_FIELDASSIGN
412                    || transferType == TT_GLOBINIT
413                    || transferType == TT_FCNPASS)
414             {
415               ; /* no error */
416             }
417           else if (transferType == TT_PARAMRETURN)
418             {
419               if (optgenerror 
420                   (code,
421                    message
422                    ("%s storage %qreachable from %s parameter",
423                     exkind_capName (sRef_getExKind (fref)),
424                     sRef_unparseOpt (fref), 
425                     exkind_unparseError (sRef_getExKind (tref))),
426                    loc))
427                 {
428                   sRef_showExpInfo (fref);
429                   sRef_setExKind (fref, XO_UNKNOWN, loc);
430                 }
431             }
432           else if (transferType == TT_LEAVETRANS)
433             {
434               ;
435             }
436           else if (transferType == TT_GLOBINIT)
437             {
438               if (optgenerror 
439                   (code,
440                    message 
441                    ("%s storage %qreachable from %s initial value",
442                     exkind_capName (sRef_getExKind (fref)),
443                     sRef_unparseOpt (fref), 
444                     exkind_unparseError (sRef_getExKind (tref))),
445                    loc))
446                 {
447                   sRef_showExpInfo (fref);
448                   sRef_setExKind (fref, XO_UNKNOWN, loc);
449                 }
450             }
451           else if (transferType == TT_GLOBRETURN)
452             {
453               if (optgenerror 
454                   (code,
455                    message
456                    ("%s storage %qreachable from %s global",
457                     exkind_capName (sRef_getExKind (fref)),
458                     sRef_unparseOpt (fref), 
459                     exkind_unparseError (sRef_getExKind (tref))),
460                    loc))
461                 {
462                   sRef_showExpInfo (fref);
463                   sRef_setExKind (fref, XO_UNKNOWN, loc);
464                 }
465             }
466           else if (transferType == TT_FCNRETURN)
467             {
468               if (optgenerror 
469                   (code,
470                    message 
471                    ("%s storage %qreachable from %s return value",
472                     exkind_capName (sRef_getExKind (fref)),
473                     sRef_unparseOpt (fref), 
474                     exkind_unparseError (sRef_getExKind (tref))),
475                    loc))
476                 {
477                   sRef_showExpInfo (fref);
478                   sRef_setExKind (fref, XO_UNKNOWN, loc);
479                 }
480             }
481           else
482             {
483               llcontbug (message ("Transfer type: %s", 
484                                   transferType_unparse (transferType)));
485               
486               if (optgenerror 
487                   (code,
488                    message
489                    ("%s storage %qreachable from %s return value",
490                     exkind_capName (sRef_getExKind (fref)),
491                     sRef_unparseOpt (fref), 
492                     exkind_unparseError (sRef_getExKind (tref))),
493                    loc))
494                 {
495                   sRef_showExpInfo (fref);
496                   sRef_setExKind (fref, XO_UNKNOWN, loc);
497                 }
498             }
499
500         }
501       
502       if (!alkind_compatible (fkind, tkind))
503         {
504           if (fkind == AK_UNKNOWN && !sRef_isStateLive (fref))
505             {
506               ; /* no error (will be a definition error) */
507             }
508           else if (transferType == TT_DOASSIGN
509                    || transferType == TT_FIELDASSIGN) /* evans 2002-02-05 - added TT_FIELDASSIGN */
510             {
511               ; /* no error */
512             }
513           else if (transferType == TT_FCNPASS)
514             {
515               if (alkind_isKnown (sRef_getAliasKind (tref)))
516                 {
517                   if (optgenerror 
518                       (FLG_COMPMEMPASS,
519                        message
520                        ("Storage %qreachable from passed parameter "
521                         "is %s (should be %s): %s",
522                         sRef_unparseOpt (fref), 
523                         alkind_unparse (sRef_getAliasKind (fref)),
524                         alkind_unparse (sRef_getAliasKind (tref)),
525                         exprNode_unparse (fexp)),
526                        loc))
527                     {
528                       sRef_showAliasInfo (fref);
529                     }
530                 }
531             }
532           else if (transferType == TT_PARAMRETURN)
533             {
534               bool noerror = FALSE;
535
536               if (alkind_isDependent (sRef_getAliasKind (fref)))
537                 {
538                   if (canLoseLocalReference (fref, loc))
539                     {
540                       noerror = TRUE;
541                     }
542                 }
543
544               if (!noerror
545                   && optgenerror 
546                   (FLG_COMPMEMPASS,
547                    message
548                    ("Storage %qreachable from parameter is %s (should be %s)",
549                     sRef_unparseOpt (fref), 
550                     alkind_unparse (sRef_getAliasKind (fref)),
551                     alkind_unparse (sRef_getAliasKind (tref))),
552                    loc))
553                 {
554                   sRef_showAliasInfo (fref);
555                 }
556               }
557           else if (transferType == TT_LEAVETRANS)
558             {
559               if (optgenerror 
560                   (FLG_COMPMEMPASS,
561                    message
562                    ("Storage %qreachable from temporary reference is %s "
563                     "at scope exit (should be %s)",
564                     sRef_unparseOpt (fref), 
565                     alkind_unparse (sRef_getAliasKind (fref)),
566                     alkind_unparse (sRef_getAliasKind (tref))),
567                    loc))
568                 {
569                   sRef_showAliasInfo (fref);
570                 }
571               }
572           else if (transferType == TT_GLOBRETURN)
573             {
574               if (optgenerror 
575                   (FLG_COMPMEMPASS,
576                    message
577                    ("Storage %qreachable from global is %s (should be %s)",
578                     sRef_unparseOpt (fref), 
579                     alkind_unparse (sRef_getAliasKind (fref)),
580                     alkind_unparse (sRef_getAliasKind (tref))),
581                    loc))
582                 {
583                   sRef_showAliasInfo (fref);
584                 }
585             }
586           else if (transferType == TT_FCNRETURN)
587             {
588               if (optgenerror 
589                   (FLG_COMPMEMPASS,
590                    message 
591                    ("Storage %qreachable from return value is %s (should be %s)",
592                     sRef_unparseOpt (fref), 
593                     alkind_unparse (sRef_getAliasKind (fref)),
594                     alkind_unparse (sRef_getAliasKind (tref))),
595                    loc))
596                 {
597                   sRef_showAliasInfo (fref);
598                 }
599             }
600           else if (transferType == TT_GLOBINIT)
601             {
602               if (optgenerror 
603                   (FLG_COMPMEMPASS,
604                    message 
605                    ("Storage %qreachable from initial value is %s (should be %s)",
606                     sRef_unparseOpt (fref), 
607                     alkind_unparse (sRef_getAliasKind (fref)),
608                     alkind_unparse (sRef_getAliasKind (tref))),
609                    loc))
610                 {
611                   sRef_showAliasInfo (fref);
612                 }
613             }
614           else
615             {
616               llcontbug (message ("Transfer type: %s", 
617                                   transferType_unparse (transferType)));
618               
619               if (optgenerror 
620                   (FLG_COMPMEMPASS,
621                    message
622                    ("Storage %qreachable from return value is %s (should be %s)",
623                     sRef_unparseOpt (fref), 
624                     alkind_unparse (sRef_getAliasKind (fref)),
625                     alkind_unparse (sRef_getAliasKind (tref))),
626                    loc))
627                 {
628                   sRef_showAliasInfo (fref);
629                 }
630             }
631         }
632
633       if (sRef_isDead (fref))
634         {
635           if (directUnion)
636             {
637               return NO;
638             }
639
640           if (transferType == TT_PARAMRETURN)
641             {
642               if (optgenerror 
643                   (FLG_USERELEASED,
644                    message 
645                    ("Released storage %q reachable from parameter at return point",
646                     sRef_unparse (fref)),
647                    loc))
648                 {
649                   sRef_showStateInfo (fref);
650                   return YES;
651                 }
652               }
653           else if (transferType == TT_LEAVETRANS)
654             {
655               if (optgenerror 
656                   (FLG_USERELEASED,
657                    message ("Released storage %q reachable from temporary "
658                             "reference at scope exit",
659                             sRef_unparse (fref)),
660                    loc))
661                 {
662                   sRef_showStateInfo (fref);
663                   return YES;
664                 }
665               }
666           else if (transferType == TT_GLOBRETURN)
667             {
668               if (optgenerror 
669                   (FLG_GLOBSTATE,
670                    message ("Released storage %q reachable from global",
671                             sRef_unparse (fref)),
672                    loc))
673                 {
674                   sRef_showStateInfo (fref);
675                   return YES;
676                 }
677             }
678           else if (transferType == TT_FCNPASS)
679             {
680               if (optgenerror 
681                   (FLG_USERELEASED,
682                    message ("Released storage %q reachable from passed parameter",
683                             sRef_unparse (fref)),
684                    loc))
685                 {
686                   sRef_showStateInfo (fref);
687                   return YES;
688                 }
689             }
690           else
691             {
692               if (optgenerror 
693                   (FLG_USERELEASED,
694                    message ("Released storage %q reachable from parameter",
695                             sRef_unparse (fref)),
696                    loc))
697                 {
698                   sRef_showStateInfo (fref);
699                   return YES;
700                 }
701             }
702         }
703     }
704
705   if (!topLevel 
706       && sRef_possiblyNull (fref) 
707       && !sRef_perhapsNull (tref) 
708       && ctype_isRealPointer (sRef_getType (tref))
709       && !usymtab_isGuarded (fref))
710     {
711       if (transferType == TT_FCNRETURN)
712         {
713           if (optgenerror 
714               (FLG_NULLRET, 
715                message ("%q storage %qderivable from return value: %s", 
716                         cstring_capitalize (sRef_nullMessage (fref)),
717                         sRef_unparseOpt (fref),
718                         exprNode_unparse (fexp)),
719                loc))
720             {
721               sRef_showNullInfo (fref);
722
723               DPRINTF (("fref: %s", sRef_unparseFull (fref)));
724               DPRINTF (("tref: %s", sRef_unparseFull (tref)));
725
726               sRef_setNullError (fref);
727             }
728         }
729       else if (transferType == TT_GLOBRETURN || transferType == TT_PARAMRETURN)
730         {
731           if (optgenerror 
732               (FLG_NULLSTATE,
733                message 
734                ("Function returns with %s storage derivable from %q %q", 
735                 sRef_nullMessage (fref),
736                 cstring_makeLiteral ((transferType == TT_GLOBRETURN) 
737                                      ? "global" : "parameter"),
738                 sRef_unparse (fref)),
739                loc))
740             {
741               sRef_showNullInfo (fref);
742               sRef_setNullError (fref);
743             }
744         }
745       else if (transferType == TT_GLOBPASS)
746         {
747           if (optgenerror
748               (FLG_NULLPASS,
749                message ("Function called with %s storage "
750                         "derivable from global %q", 
751                         sRef_nullMessage (fref),
752                         sRef_unparse (fref)),
753                loc))
754             {
755               sRef_showNullInfo (fref);
756               sRef_setNullError (fref);
757             }
758         }
759       else if (transferType == TT_FCNPASS)
760         {
761           if (optgenerror
762               (FLG_NULLSTATE,
763                message ("%q storage %qderivable from parameter %q", 
764                         cstring_capitalize (sRef_nullMessage (fref)),
765                         sRef_unparseOpt (fref),
766                         generateText (fexp, exprNode_undefined, 
767                                       sRef_undefined, TT_FCNPASS)),
768                loc))
769             {
770               DPRINTF (("fref: %s", sRef_unparseFull (fref)));
771               DPRINTF (("tref: %s", sRef_unparseFull (tref)));
772               sRef_showNullInfo (fref);
773               sRef_setNullError (fref);
774             }
775         }
776       else
777         {
778           llassert (transferType == TT_DOASSIGN
779                     || transferType == TT_FIELDASSIGN /* evans 2002-02-05: no warnings for local fields */
780                     || transferType == TT_GLOBINIT
781                     || transferType == TT_LEAVETRANS);
782         }
783     }
784
785   if (sRef_isRelDef (tref) 
786       || sRef_isPartial (tref) 
787       || sRef_isAllocated (tref)
788       || sRef_isStateSpecial (tref))
789     {
790       /* should check fref is allocated? */
791       return YES;
792     }
793
794   ct = ctype_realType (sRef_getType (fref));
795
796   DPRINTF (("Here: %s", ctype_unparse (ct)));
797
798   if (!(sRef_isAnyDefined (fref) 
799         || sRef_isPdefined (fref)
800         || sRef_isAllocated (fref)
801         || sRef_isStateUnknown (fref)))
802     {
803       if (transferType == TT_GLOBRETURN)
804         {
805           if (report
806               && optgenerror 
807               (FLG_COMPDEF,
808                message ("Function returns with global %q not "
809                         "completely defined%q",
810                         sRef_unparse (sRef_getRootBase (fref)),
811                         defExpl (fref)),
812                loc))
813             {
814               sRef_showStateInfo (fref);
815               sRef_setDefined (fref, loc);
816             }
817         }
818       else if (transferType == TT_GLOBPASS)
819         {
820           if (report &&
821               optgenerror 
822               (FLG_COMPDEF,
823                message 
824                ("Function called with global %q not completely defined%q",
825                 sRef_unparse (sRef_getRootBase (fref)),
826                 defExpl (fref)),
827                loc))
828             {
829               sRef_showStateInfo (fref);
830               sRef_setDefined (fref, loc);
831             }
832         }
833       else if (transferType == TT_PARAMRETURN)
834         {
835           if (report && !topLevel
836               && optgenerror 
837               (FLG_COMPDEF,
838                message ("Function returns storage %q reachable from parameter not "
839                         "completely defined%q",
840                         sRef_unparse (ofref),
841                         defExpl (fref)),
842                loc))
843             {
844               sRef_showStateInfo (fref);
845               sRef_setDefined (fref, loc);
846             }
847         }
848       else if (transferType == TT_LEAVETRANS)
849         {
850           if (report && !topLevel
851               && optgenerror 
852               (FLG_COMPDEF,
853                message ("Scope exits with storage %q reachable from "
854                         "temporary reference not completely defined%q",
855                         sRef_unparse (ofref),
856                         defExpl (fref)),
857                loc))
858             {
859               sRef_showStateInfo (fref);
860               sRef_setDefined (fref, loc);
861             }
862         }
863       else 
864         {
865           if (transferType != TT_DOASSIGN
866               && (!(sRef_isNew (fref) || sRef_isType (fref))))
867             {
868               if (report)
869                 {
870                   DPRINTF (("Here we are: %s", sRef_unparseFull (fref)));
871
872                   if (sRef_isDead (fref))
873                     {
874                       if (optgenerror 
875                           (FLG_USERELEASED,
876                            message ("%s storage %qwas released: %q",
877                                     transferType_unparse (transferType),
878                                     sRef_unparseOpt (fref), 
879                                     generateText (fexp, texp, tref, transferType)),
880                            loc))
881                         {
882                           sRef_showStateInfo (fref);
883                         }
884                     }
885                   else 
886                     {
887                       if (optgenerror 
888                           (FLG_COMPDEF,
889                            message 
890                            ("%s storage %qnot completely defined%q: %q",
891                             transferType_unparse (transferType),
892                             sRef_unparseOpt (ofref),
893                             defExpl (fref),
894                             generateText (fexp, texp, tref, transferType)),
895                            loc))
896                         {
897                           sRef rb = sRef_getRootBase (fref);
898                           sRef_showStateInfo (fref);
899                           
900                           sRef_setDefinedCompleteDirect (rb, loc);
901                         }
902                     }
903                 }
904             }
905           else
906             {
907
908               if (sRef_isAllocated (fref) && sRef_isValid (tref) 
909                   && (transferType == TT_DOASSIGN))
910                 {
911                   sRef_setAllocatedComplete (tref, loc);
912                 }
913               return YES;
914             }
915         }
916
917       return NO;
918     }
919   
920   if (ctype_isUnknown (ct))
921     {
922       return YES;
923     }
924   else if (ctype_isPointer (ct) || ctype_isArray (ct)) /* evans 2001-07-12 added ctype_isArray */
925     {
926       ctype tct = ctype_realType (sRef_getType (tref));
927
928       if (sRef_isStateUnknown (fref))
929         {
930           return NO;
931         }
932       else
933         {
934           DPRINTF (("Here fref: %s", sRef_unparseFull (fref)));
935           DPRINTF (("Here tref: %s", sRef_unparseFull (tref)));
936
937           if (ctype_isAP (tct) || ctype_isUnknown (tct))
938             {
939               sRef fptr = sRef_constructDeref (fref);
940               sRef tptr = sRef_constructDeref (tref);
941
942               DPRINTF (("Here tptr: %s", sRef_unparseFull (tptr)));
943
944               return (checkCompletelyDefined (fexp, fptr, ofref,
945                                               texp, tptr,
946                                               FALSE, inUnion, FALSE, loc, 
947                                               transferType, depth + 1, report));
948             }
949           else
950             {
951               return YES;
952             }
953         }
954     }
955   else if (ctype_isStruct (ct))
956     {
957       ctype tct = ctype_realType (sRef_getType (tref));
958
959       DPRINTF (("Struct defined: %s", ctype_unparse (tct)));
960
961       if (ctype_match (ct, tct))
962         {
963           bool isOk = TRUE;
964           bool hasOneDefined = FALSE;
965           cstringSList badFields = cstringSList_undefined;
966           
967           if (sRef_isStateUnknown (fref) || sRef_isAllocated (tref)) 
968             {
969               return YES;
970             }
971           
972           DPRINTF (("Check field: %s", sRef_unparseFull (fref)));
973
974           if (sRef_isPdefined (fref) || sRef_isAnyDefined (fref))
975             {
976               DPRINTF (("Is defined: %s", sRef_unparse (fref)));
977
978               sRefSet_realElements (sRef_derivedFields (fref), sr)
979                 {
980                   bool thisField;
981                   
982                   hasOneDefined = TRUE;
983                   
984                   DPRINTF (("Check derived: %s", sRef_unparseFull (sr)));
985
986                   if (sRef_isField (sr))
987                     {
988                       cstring fieldname = sRef_getField (sr);
989                       sRef fldref = sRef_makeField (tref, fieldname);
990                       bool shouldCheck = !sRef_isRecursiveField (fldref);
991                         
992                       if (shouldCheck)
993                         {
994                           thisField = 
995                             ynm_toBoolRelaxed 
996                             (checkCompletelyDefined (fexp, sr, ofref,
997                                                      texp, fldref,
998                                                      FALSE, inUnion, FALSE, loc, 
999                                                      transferType, depth + 1, 
1000                                                      FALSE));
1001                         }
1002                       else
1003                         {
1004                           thisField = TRUE;
1005                         }
1006                       
1007                       if (!thisField)
1008                         {
1009                           isOk = FALSE;
1010                           badFields = cstringSList_add (badFields,
1011                                                         sRef_getField (sr));
1012                         }
1013                     }
1014                 } end_sRefSet_realElements;
1015             }
1016           else if (sRef_isAllocated (fref))
1017             {
1018               /*
1019               ** for structures, each field must be completely defined
1020               */
1021               
1022               uentryList fields = ctype_getFields (ct);
1023               
1024               uentryList_elements (fields, ue)
1025                 {
1026                   bool thisField;
1027                   cstring name = uentry_getRealName (ue);
1028                   sRef ffield = sRef_makeField (fref, name);
1029                   sRef tfield = sRef_makeField (tref, name);
1030                   bool shouldCheck = !sRef_isRecursiveField (tfield);
1031                   
1032                   if (!shouldCheck)
1033                     {
1034                       thisField = TRUE;
1035                     }
1036                   else
1037                     {
1038                       thisField = ynm_toBoolRelaxed
1039                         (checkCompletelyDefined (fexp, ffield, ofref,
1040                                                  texp, tfield,
1041                                                  FALSE, inUnion, FALSE,
1042                                                  loc, transferType,
1043                                                  depth + 1, FALSE));
1044                     }
1045                   
1046                   if (!thisField)
1047                     {
1048                       isOk = FALSE;
1049                       badFields = cstringSList_add (badFields, uentry_rawName (ue));
1050                     }
1051                   else
1052                     {
1053                       hasOneDefined = TRUE;
1054                     }
1055                 } end_uentryList_elements;
1056             }
1057           else
1058             {
1059               DPRINTF (("Not checking: %s", sRef_unparseFull (fref)));
1060             }
1061           
1062           if (!isOk && (!inUnion || hasOneDefined))
1063             {
1064               if (transferType == TT_GLOBRETURN)
1065                 {
1066                   if (optgenerror
1067                       (FLG_COMPDEF,
1068                        message ("Global storage %q contains %d undefined field%& "
1069                                 "when call returns: %q",
1070                                 sRef_unparse (fref),
1071                                 cstringSList_size (badFields),
1072                                 cstringSList_unparseAbbrev (badFields)),
1073                        loc))
1074                     {
1075                       sRef_setDefined (fref, loc);
1076                     }
1077                 }
1078               else if (transferType == TT_GLOBPASS)
1079                 {
1080                   if (optgenerror
1081                       (FLG_COMPDEF,
1082                        message ("Global storage %q contains %d undefined field%& "
1083                                 "before call: %q",
1084                                 sRef_unparse (fref),
1085                                 cstringSList_size (badFields),
1086                                 cstringSList_unparseAbbrev (badFields)),
1087                        loc))
1088                     {
1089                       sRef_setDefined (fref, loc);
1090                     }
1091                 }
1092               else if (transferType == TT_PARAMRETURN)
1093                 {
1094                   if (optgenerror
1095                       (FLG_COMPDEF,
1096                        message ("Storage %qreachable from parameter "
1097                                 "contains %d undefined field%&: %q",
1098                                 sRef_unparseOpt (fref),
1099                                 cstringSList_size (badFields),
1100                                 cstringSList_unparseAbbrev (badFields)),
1101                        loc))
1102                     {
1103                       sRef_setDefined (fref, loc);
1104                     }
1105                 }
1106               else if (transferType == TT_LEAVETRANS)
1107                 {
1108                   /* no error */
1109                 }
1110               else
1111                 {
1112                   if (optgenerror
1113                       (FLG_COMPDEF,
1114                        message ("%s storage %qcontains %d undefined field%&: %q",
1115                                 transferType_unparse (transferType),
1116                                 sRef_unparseOpt (fref),
1117                                 cstringSList_size (badFields),
1118                                 cstringSList_unparseAbbrev (badFields)),
1119                        loc))
1120                     {
1121                       sRef_setDefined (fref, loc);
1122                     }
1123                 }
1124             }
1125           
1126           cstringSList_free (badFields);
1127           
1128           if (inUnion)
1129             {
1130               if (directUnion)
1131                 {
1132                   return (ynm_fromBool (hasOneDefined));
1133                 }
1134               else
1135                 {
1136                   return (MAYBE);
1137                 }
1138             }
1139           else
1140             {
1141               return (ynm_fromBool (!report || isOk));
1142             }
1143         }
1144       else
1145         {
1146           return YES;
1147         }
1148     }
1149   else if (ctype_isUnion (ct))
1150     {
1151       if (sRef_isStateUnknown (fref) || sRef_isAllocated (tref)) 
1152         {
1153           return YES;
1154         }
1155       else 
1156         {
1157           ctype tct = ctype_realType (sRef_getType (tref));
1158           
1159           if (ctype_isKnown (tct) && ctype_match (ct, tct))
1160             {
1161               cstringSList goodFields = cstringSList_new ();
1162               bool isOk = FALSE;
1163               int nelements = sRefSet_size (sRef_derivedFields (fref));       
1164
1165               /*
1166               ** for unions, at least one field must be completely defined
1167               */
1168               
1169               if (sRef_isPdefined (fref) || sRef_isAnyDefined (fref))
1170                 {
1171                   isOk = TRUE;
1172                 }
1173               
1174               sRefSet_realElements (sRef_derivedFields (fref), sr)
1175                 {
1176                   bool thisField;
1177
1178                   if (sRef_isField (sr))
1179                     {
1180                       sRef fldref = sRef_makeField (tref, sRef_getField (sr));
1181
1182                       DPRINTF (("Trying union field: %s", sRef_unparseFull (fldref)));
1183
1184                       thisField = ynm_toBoolStrict 
1185                         (checkCompletelyDefined 
1186                          (fexp, sr, ofref,
1187                           texp, fldref, FALSE, inUnion, 
1188                           (nelements > 1 ? TRUE : FALSE),
1189                           loc, transferType, depth + 1, FALSE));
1190                       
1191                       if (thisField)
1192                         {
1193                           goodFields = cstringSList_add 
1194                             (goodFields, sRef_getField (sr));
1195                         }
1196                     }
1197                 } end_sRefSet_realElements;
1198               
1199               if (cstringSList_empty (goodFields) 
1200                   && !isOk 
1201                   && context_getFlag (FLG_UNIONDEF))
1202                 {
1203                   if (!inUnion)
1204                     {
1205                       if (transferType == TT_PARAMRETURN)
1206                         {
1207                           voptgenerror 
1208                             (FLG_UNIONDEF,
1209                              message ("Union %q reachable from parameter has "
1210                                       "no defined field",
1211                                       sRef_unparse (fref)),
1212                              loc);
1213                         }
1214                       else if (transferType == TT_LEAVETRANS)
1215                         {
1216                           voptgenerror 
1217                             (FLG_UNIONDEF,
1218                              message ("Union %q has no defined field at scope exit",
1219                                       sRef_unparse (fref)),
1220                              loc);
1221                         }
1222                       /* evans 2001-08-21: added this branch for global returns */
1223                       else if (transferType == TT_GLOBRETURN)
1224                         {
1225                           voptgenerror 
1226                             (FLG_UNIONDEF,
1227                              message ("Union %q reachable from global %q has "
1228                                       "no defined field",
1229                                       sRef_unparse (fref),
1230                                       sRef_unparse (sRef_getRootBase (fref))),
1231                              loc);
1232                         }
1233                       else if (transferType == TT_DOASSIGN
1234                                || transferType == TT_FIELDASSIGN
1235                                || transferType == TT_GLOBINIT)
1236                         {
1237                           ; /* no error */
1238                         }
1239                       else
1240                         {
1241                           voptgenerror 
1242                             (FLG_UNIONDEF,
1243                              message ("%s union %q has no defined field",
1244                                       transferType_unparse (transferType),
1245                                       sRef_unparse (fref)),
1246                              loc);
1247                         }
1248                     }
1249                   isOk = FALSE;
1250                 }
1251               
1252               cstringSList_free (goodFields);
1253               return ynm_fromBool (!report || isOk);
1254             }
1255         }
1256     }
1257   else
1258     {
1259       ;
1260     }
1261
1262   return YES;
1263 }
1264
1265 /*
1266 ** fref is being free'd
1267 */
1268
1269 typedef enum {
1270   DSC_GLOB, DSC_LOCAL, DSC_PARAM, DSC_STRUCT
1271   } dscCode;
1272
1273 static /*@observer@*/ cstring dscCode_unparse (dscCode desc) /*@*/
1274 {
1275   switch (desc)
1276     {
1277     case DSC_GLOB:
1278       return cstring_makeLiteralTemp ("killed global");
1279     case DSC_LOCAL:
1280       return cstring_makeLiteralTemp ("variable declared in this scope");
1281     case DSC_PARAM:
1282       return cstring_makeLiteralTemp ("released storage");
1283     case DSC_STRUCT:
1284       return cstring_makeLiteralTemp ("released structure parameter");
1285     }
1286
1287   BADEXIT;
1288 }
1289
1290 static bool 
1291 checkCompletelyDestroyed (exprNode p_fexp, sRef p_fref, bool p_topLevel, bool p_isField,
1292                           fileloc p_loc, int p_depth, dscCode p_desc,
1293                           bool p_hideErrors);
1294
1295 bool transferChecks_globalDestroyed (sRef fref, fileloc loc)
1296 {
1297   DPRINTF (("Global destroyed: %s", sRef_unparseFull (fref)));
1298   return (checkCompletelyDestroyed (exprNode_undefined, fref, TRUE, FALSE,
1299                                     loc, 0, DSC_GLOB, FALSE));
1300 }
1301
1302 void transferChecks_localDestroyed (sRef fref, fileloc loc)
1303 {
1304   if (sRef_isObserver (fref) || sRef_isExposed (fref)
1305       || sRef_isPartial (fref))
1306     {
1307       ;
1308     }
1309   else
1310     {
1311       (void) checkCompletelyDestroyed (exprNode_undefined, fref, TRUE, FALSE,
1312                                        loc, 0, DSC_LOCAL, FALSE);
1313     }
1314 }
1315
1316 void transferChecks_structDestroyed (sRef fref, fileloc loc)
1317 {
1318   DPRINTF (("Check struct destroyed: %s", sRef_unparse (fref)));
1319
1320   if (sRef_isObserver (fref) || sRef_isExposed (fref)
1321       || sRef_isPartial (fref))
1322     {
1323       DPRINTF (("Its exposed!"));;
1324     }
1325   else
1326     {
1327       (void) checkCompletelyDestroyed (exprNode_undefined, fref, TRUE, FALSE,
1328                                        loc, 0, DSC_STRUCT, FALSE);
1329     }
1330 }
1331
1332 static bool
1333 checkCompletelyDestroyed (exprNode fexp, sRef fref, bool topLevel, bool isField,
1334                           fileloc loc, int depth,
1335                           dscCode desc, bool hideErrors)
1336 {
1337   ctype ct;
1338   
1339   DPRINTF (("Check completely destroyed: %s / %s",
1340             sRef_unparse (fref),
1341             bool_unparse (hideErrors)));
1342
1343   if (depth > MAXDEPTH)
1344     {
1345       llquietbug (message ("checkCompletelyDestroyed: too deep: %s / %q", 
1346                            exprNode_unparse (fexp),
1347                            sRef_unparseFull (fref)));
1348       return TRUE;
1349     }
1350
1351   if (!sRef_isKnown (fref)) return TRUE;
1352
1353   /* evans 2001-03-24: added this.  Definitely null values are always destroyed. */
1354
1355   if (sRef_isDefinitelyNull (fref))
1356     {
1357       return TRUE;
1358     }
1359
1360   if (sRef_isDependent (fref) || sRef_isShared (fref) || sRef_isKept (fref))
1361     {
1362       return TRUE;
1363     }
1364
1365   {
1366     /*
1367     ** evans 2001-03-24: if there is a dependent reference to this storage,
1368     **    no need to destroy, but make it responsible.
1369     */
1370                                                          
1371     sRef depRef = dependentReference (fref);
1372
1373     DPRINTF (("Destroyed? %s / %s",
1374               sRef_unparseFull (fref),
1375               sRef_unparseFull (depRef)));
1376
1377     DPRINTF (("Aliases: %s", usymtab_unparseAliases ()));
1378
1379     if (sRef_isValid (depRef))
1380       {
1381         /*
1382         ** If the referenced storage was not dependent, we make
1383         ** the reference the owner since it must eventually be
1384         ** destroyed.
1385         */
1386
1387         if (!sRef_isDependent (depRef)) 
1388           {
1389             sRef_setOnly (depRef, loc); /* could be owned? */
1390           }
1391
1392         sRef_kill (fref, loc);
1393         return TRUE;
1394       }
1395   }
1396
1397   ct = ctype_realType (sRef_getType (fref));
1398
1399   if (sRef_isPdefined (fref) 
1400       && ctype_isAP (ct)
1401       && !isField
1402       && !context_getFlag (FLG_STRICTDESTROY))
1403     {
1404       /*
1405       ** Don't report errors for array elements (unless strictdestroy)
1406       ** when at least one appears to have been destroyed.
1407       */
1408
1409       DPRINTF (("Partial: %s / hiding errors: %s", sRef_unparseFull (fref),
1410                 ctype_unparse (ct)));
1411       hideErrors = TRUE;
1412       /* Don't report any more errors, but still change ownership. */
1413     }
1414   
1415   if (usymtab_isDefinitelyNull (fref)) 
1416     {
1417       DPRINTF (("Probably null!"));
1418       return TRUE;
1419     }
1420
1421   /*
1422   ** evans 2002-01-02: removed this
1423   ** if (!context_flagOn (FLG_COMPDESTROY, loc)) 
1424   ** {
1425   ** return TRUE;
1426   ** }
1427   ** 
1428   ** if (!context_getFlag (FLG_MUSTFREEONLY)) return TRUE;
1429   */
1430   
1431   DPRINTF (("Here: %s", ctype_unparse (ct)));
1432
1433   if (!topLevel)
1434     {
1435       bool docheck = FALSE;
1436       bool reportederror;
1437
1438       if (sRef_isFresh (fref) || sRef_isOnly (fref))
1439         {
1440           docheck = TRUE;
1441           
1442           DPRINTF (("Here: %s", ctype_unparse (ct)));
1443           if (sRef_isDead (fref) 
1444               || sRef_isUnuseable (fref)
1445               || sRef_definitelyNull (fref)
1446               || sRef_isObserver (fref) 
1447               || sRef_isExposed (fref))
1448             {
1449               docheck = FALSE;
1450             }
1451         }
1452       
1453       if (docheck)
1454         {
1455           if (sRef_isPossiblyDead (fref) || sRef_isRelDef (fref))
1456             {
1457               if (exprNode_isDefined (fexp))
1458                 {
1459                   reportederror = 
1460                     !hideErrors 
1461                     && 
1462                     optgenerror2 
1463                     (FLG_COMPDESTROY, FLG_STRICTDESTROY,
1464                      message ("Only storage %q (type %s) derived from %s "
1465                               "may not have been released: %s",
1466                               sRef_unparse (fref), 
1467                               ctype_unparse (sRef_getType (fref)),
1468                               dscCode_unparse (desc),
1469                               exprNode_unparse (fexp)),
1470                      loc);
1471                 }
1472               else
1473                 {
1474                   reportederror =
1475                     !hideErrors
1476                     &&
1477                     optgenerror2 
1478                     (FLG_COMPDESTROY, FLG_STRICTDESTROY,
1479                      message 
1480                      ("Only storage %q (type %s) derived from %s "
1481                       "may not have been released",
1482                       sRef_unparse (fref), 
1483                       ctype_unparse (sRef_getType (fref)),
1484                       dscCode_unparse (desc)),
1485                      loc);
1486                 }
1487               
1488               if (reportederror)
1489                 {
1490                   sRef_kill (fref, loc); /* prevent further errors */
1491                 }
1492             }
1493           else 
1494             {
1495               if (sRef_isStateUndefined (fref))
1496                 {
1497                   DPRINTF (("Here: %s", ctype_unparse (ct)));
1498                   return TRUE;
1499                 }
1500               else
1501                 {
1502                   if (exprNode_isDefined (fexp))
1503                     {
1504                       DPRINTF (("Here: %s", sRef_unparseFull (fref)));
1505
1506                       reportederror =
1507                         !hideErrors
1508                         &&
1509                         optgenerror 
1510                         (FLG_COMPDESTROY,
1511                          message ("Only storage %q (type %s) derived from %s "
1512                                   "is not released (memory leak): %s",
1513                                   sRef_unparse (fref),
1514                                   ctype_unparse (sRef_getType (fref)),  
1515                                   dscCode_unparse (desc),
1516                                   exprNode_unparse (fexp)),
1517                          loc);
1518                     }
1519                   else
1520                     {
1521                       reportederror = 
1522                         !hideErrors
1523                         &&
1524                         optgenerror 
1525                         (FLG_COMPDESTROY,
1526                          message ("Only storage %q (type %s) derived from %s "
1527                                   "is not released (memory leak)",
1528                                   sRef_unparse (fref),
1529                                   ctype_unparse (sRef_getType (fref)),
1530                                   dscCode_unparse (desc)),
1531                          loc);
1532                     }
1533
1534                   if (reportederror)
1535                     {
1536                       hideErrors = TRUE;
1537                       
1538                       /* sRef_kill (fref, loc); */ /* prevent further errors */
1539                       DPRINTF (("Killed: %s", sRef_unparseFull (fref)));
1540                     }
1541                 }
1542             }
1543
1544           DPRINTF (("Here: %s", ctype_unparse (ct)));
1545           return FALSE;
1546         }
1547       
1548       if (/*! evs-2002-03-24 sRef_isAnyDefined (fref) || */
1549           sRef_isDead (fref)
1550           || (sRef_isPdefined (fref) 
1551               && sRefSet_isEmpty (sRef_derivedFields (fref)))) 
1552         {
1553           DPRINTF (("Here: %s [%s / %s]", 
1554                     sRef_unparseFull (fref),
1555                     bool_unparse (sRef_isAnyDefined (fref)),
1556                     bool_unparse (sRef_isDead (fref))));
1557           return TRUE; 
1558         }
1559     }
1560
1561   DPRINTF (("Here..."));
1562
1563   if (ctype_isPointer (ct))
1564     {
1565       sRef fptr = sRef_constructDeadDeref (fref);
1566       bool res;
1567
1568       res = checkCompletelyDestroyed (fexp, fptr, FALSE, FALSE,
1569                                       loc, depth + 1, desc, hideErrors);
1570       
1571       return res;
1572     }
1573   else if (ctype_isArray (ct))
1574     {
1575       if ((sRef_isStateUnknown (fref) || sRef_isAllocated (fref))
1576           && !sRef_hasDerived (fref))
1577         {
1578           /*
1579           ** Bogosity necessary to prevent infinite depth.
1580           */
1581
1582           return FALSE;
1583         }
1584       else
1585         {
1586           sRef farr = sRef_constructDeadDeref (fref);
1587           
1588           return (checkCompletelyDestroyed (fexp, farr, FALSE, FALSE,
1589                                             loc, depth + 1, desc, hideErrors));
1590         }
1591     }
1592   else if (ctype_isStruct (ct))
1593     {
1594       /*
1595       ** for structures, each field must be completely destroyed
1596       */
1597
1598       bool isOk = TRUE;
1599       uentryList fields = ctype_getFields (ct);
1600
1601       DPRINTF (("Struct fields: %s", uentryList_unparse (fields)));
1602
1603       if (depth >= MAXDEPTH)
1604         {
1605           llquietbug (message ("checkCompletelyDestroyed (fields): too deep: %s / %q", 
1606                                exprNode_unparse (fexp),
1607                                sRef_unparseFull (fref)));
1608                               
1609           return TRUE;
1610         }
1611       else
1612         {
1613           uentryList_elements (fields, ue)
1614             {
1615               sRef field = sRef_makeField (fref, uentry_rawName (ue));
1616               
1617               /*
1618               ** note order of && operands --- want to report multiple errors
1619               */
1620               
1621               DPRINTF (("Check field: %s", sRef_unparseFull (field)));
1622
1623               isOk = (checkCompletelyDestroyed (fexp, field, FALSE, TRUE,
1624                                                 loc, depth + 1, desc, hideErrors)
1625                       && isOk);
1626             } end_uentryList_elements;
1627         }
1628       
1629       return isOk;
1630     }
1631   else
1632     {
1633       return TRUE;
1634     }
1635 }
1636
1637 void
1638 transferChecks_return (exprNode fexp, uentry rval)
1639 {
1640   sRef uref = uentry_getSref (rval);
1641   sRef rref = sRef_makeNew (sRef_getType (uref), uref, cstring_undefined);
1642   uentry fcn = context_getHeader ();
1643   sRef fref = exprNode_getSref (fexp);
1644   stateClauseList clauses = uentry_getStateClauseList (fcn);
1645   
1646   DPRINTF (("Check return: %s as %s = %s",
1647             exprNode_unparse (fexp),
1648             sRef_unparseFull (uref),
1649             sRef_unparseFull (rref)));
1650
1651   /* evans 2001-07-18: removed: if (sRef_isStateSpecial (rref)) */
1652
1653   DPRINTF (("Check state clauses: %s",
1654             stateClauseList_unparse (clauses)));
1655   
1656   stateClauseList_postElements (clauses, cl)
1657     {
1658       if (stateClause_isGlobal (cl))
1659         {
1660           ; /*@i32@*/
1661         }
1662       else if (stateClause_setsMetaState (cl))
1663         {
1664           sRefSet refs = stateClause_getRefs (cl);
1665           qual ql = stateClause_getMetaQual (cl);
1666           annotationInfo ainfo = qual_getAnnotationInfo (ql);
1667           metaStateInfo minfo = annotationInfo_getState (ainfo);
1668           cstring key = metaStateInfo_getName (minfo);
1669           int mvalue = annotationInfo_getValue (ainfo);
1670           
1671           DPRINTF (("Return check: %s", stateClause_unparse (cl)));
1672           
1673           sRefSet_elements (refs, el)
1674             {
1675               sRef base = sRef_getRootBase (el);
1676               
1677               DPRINTF (("Sets meta state! %s", stateClause_unparse (cl)));
1678               
1679               if (sRef_isResult (base))
1680                 {
1681                   sRef sr = sRef_fixBase (el, fref);
1682                   
1683                   if (!sRef_checkMetaStateValue (sr, key, mvalue))
1684                     {
1685                       if (optgenerror 
1686                           (FLG_STATETRANSFER,
1687                            message ("Result state %q does not satisfy ensures "
1688                                     "clause: %q (state is %q, should be %s): %s",
1689                                     sRef_unparse (sr),
1690                                     stateClause_unparse (cl),
1691                                     stateValue_unparseValue (sRef_getMetaStateValue (sr, key),
1692                                                              minfo),
1693                                     metaStateInfo_unparseValue (minfo, mvalue),
1694                                     exprNode_unparse (fexp)),
1695                            exprNode_loc (fexp)))
1696                         {
1697                           sRef_showAliasInfo (sr); 
1698                           /*@i32@*/
1699                         }
1700                     }
1701                 }
1702               else 
1703                 {
1704                   /*
1705                   ** Non-results are checked in exit scope.
1706                   */
1707                 }
1708             } end_sRefSet_elements ;
1709         }
1710       else
1711         {
1712           sRefSet refs = stateClause_getRefs (cl);
1713           sRefTest tst = stateClause_getPostTestFunction (cl);
1714           sRefMod modf = stateClause_getReturnEffectFunction (cl);
1715           
1716           DPRINTF (("Clause: %s / %s",
1717                     stateClause_unparse (cl),
1718                     sRefSet_unparse (refs)));
1719           
1720           sRefSet_elements (refs, el)
1721             {
1722               sRef base = sRef_getRootBase (el);
1723               
1724               DPRINTF (("el: %s / %s", sRef_unparse (el),
1725                         sRef_unparse (base)));
1726               
1727               if (sRef_isResult (base) 
1728                   && !sRef_isDefinitelyNull (fref)) /* evans 2002-07-22: don't report allocation errors for null results */
1729                 {
1730                   sRef sr = sRef_fixBase (el, fref);
1731                   
1732                   if (tst != NULL && !(tst (sr)))
1733                     {
1734                       if (optgenerror 
1735                           (stateClause_postErrorCode (cl),
1736                            message ("%s storage %q corresponds to "
1737                                     "storage %q listed in %q clause: %s",
1738                                     stateClause_postErrorString (cl, sr),
1739                                     sRef_unparse (sr),
1740                                     sRef_unparse (el),
1741                                     stateClause_unparseKind (cl),
1742                                     exprNode_unparse (fexp)),
1743                            exprNode_loc (fexp)))
1744                         {
1745                           sRefShower ss = stateClause_getPostTestShower (cl);
1746                           
1747                           if (ss != NULL)
1748                             {
1749                               ss (sr);
1750                             }
1751                         }
1752                     }
1753                   
1754                   if (modf != NULL)
1755                     {
1756                       modf (sr, exprNode_loc (fexp));
1757                     }
1758                 }
1759               else
1760                 {
1761                   /* 
1762                   ** Non-results are checked in exit scope.
1763                   */
1764                 }
1765             } end_sRefSet_elements ;
1766         }
1767     } end_stateClauseList_postElements ;
1768   
1769   if (ctype_isRealSU (exprNode_getType (fexp)))
1770     {
1771       sRef ffref = exprNode_getSref (fexp);
1772           
1773       checkStructTransfer (exprNode_undefined, rref, 
1774                            fexp, ffref,
1775                            exprNode_loc (fexp),
1776                            TT_FCNRETURN);
1777     }
1778   else
1779     {
1780       (void) checkTransfer (fexp, exprNode_getSref (fexp),
1781                             exprNode_undefined, rref, 
1782                             exprNode_undefined,
1783                             exprNode_loc (fexp), TT_FCNRETURN);
1784     }
1785 }
1786
1787 static void
1788   checkPassstateClauseList (uentry ue, exprNode fexp, sRef fref, int argno)
1789 {
1790   stateClauseList clauses = uentry_getStateClauseList (ue);
1791
1792   DPRINTF (("Check pass special: %s / %s",
1793             exprNode_unparse (fexp), sRef_unparseFull (fref)));
1794   
1795   stateClauseList_preElements (clauses, cl)
1796     {
1797       if (stateClause_isGlobal (cl))
1798         {
1799           ;
1800         }
1801       else
1802         {
1803           sRefSet refs = stateClause_getRefs (cl);
1804           sRefTest tst = stateClause_getPreTestFunction (cl);
1805           sRefMod modf = stateClause_getEffectFunction (cl);
1806           
1807           sRefSet_elements (refs, el)
1808             {
1809               sRef base = sRef_getRootBase (el);
1810               
1811               if (sRef_isResult (base))
1812                 {
1813                   ; /* nothing to check before */
1814                 }
1815               else if (sRef_isParam (base))
1816                 {
1817                   if (sRef_getParam (base) == argno - 1)
1818                     {
1819                       sRef sb;
1820                       
1821                       DPRINTF (("Fix base: %s / %s",
1822                                 sRef_unparseFull (el),
1823                                 sRef_unparseFull (fref)));
1824                       
1825                       sb = sRef_fixBase (el, fref);
1826                       
1827                       if (tst != NULL && !(tst(sb)))
1828                         {
1829                           voptgenerror 
1830                             (stateClause_preErrorCode (cl),
1831                              message ("%s storage %qcorresponds to "
1832                                       "storage listed in %q clause of "
1833                                       "called function: %s",
1834                                       stateClause_preErrorString (cl, sb),
1835                                       sRef_unparseOpt (sb),
1836                                       stateClause_unparseKind (cl),
1837                                       exprNode_unparse (fexp)),
1838                              exprNode_loc (fexp));
1839                         }
1840                       
1841                       if (modf != NULL)
1842                         {
1843                           DPRINTF (("Fixing: %s", sRef_unparseFull (sb)));
1844                           modf (sb, exprNode_loc (fexp));
1845                           DPRINTF (("==> %s", sRef_unparseFull (sb)));
1846                         }
1847                     }
1848                 }
1849               else
1850                 {
1851                   BADBRANCH;
1852                 }
1853             } end_sRefSet_elements ;      
1854         }
1855     } end_stateClauseList_preElements ;
1856
1857     DPRINTF (("After: %s", sRef_unparseFull (fref)));
1858 }
1859
1860 /*
1861 ** should not modify arg
1862 */
1863
1864 void
1865 transferChecks_passParam (exprNode fexp, uentry arg, bool isSpec,
1866                           /*@dependent@*/ exprNode fcn, int argno, int totargs)
1867 {
1868   sRef tref = uentry_getSref (arg);
1869   sRef fref = exprNode_getSref (fexp);
1870   bool isOut = FALSE;
1871   bool isPartial = FALSE;
1872   bool isImpOut = FALSE;
1873   ctype ct = uentry_getType (arg);
1874
1875   DPRINTF (("Check pass: %s -> %s",
1876             sRef_unparseFull (fref),
1877             sRef_unparseFull (tref)));
1878   
1879   atFunction = fcn;
1880   atArgNo = argno;
1881   atNumArgs = totargs;
1882
1883   if (ctype_isElips (ct))
1884     {
1885       ct = ctype_unknown;
1886     }
1887
1888   DPRINTF (("Out arg: %s", bool_unparse (uentry_isOut (arg))));
1889
1890   if (!ctype_isElips (ct) && 
1891       (ctype_isVoidPointer (ct) && uentry_isOut (arg) && sRef_isOnly (tref)))
1892     {
1893       if (ctype_isRealAP (ct))
1894         {
1895           if (sRef_aliasCheckSimplePred (sRef_isDead, fref))
1896             {
1897               if (optgenerror
1898                   (FLG_USERELEASED,
1899                    message ("Dead storage %qpassed as out parameter to %s: %s",
1900                             sRef_unparseOpt (fref),
1901                             exprNode_unparse (fcn),
1902                             exprNode_unparse (fexp)),
1903                    exprNode_loc (fexp)))
1904                 {
1905                   if (sRef_isDead (fref))
1906                     {
1907                       sRef_showStateInfo (fref);
1908                     }
1909                   else
1910                     {
1911                       DPRINTF (("Not really dead!"));
1912                       sRef_showStateInfo (fref);
1913                     }
1914                 }
1915               
1916               sRef_setAllocated (fref, exprNode_loc (fexp));
1917             }
1918           else if (context_getFlag (FLG_STRICTUSERELEASED)
1919                    && sRef_aliasCheckSimplePred (sRef_isPossiblyDead, fref))
1920             {
1921               if (optgenerror2 
1922                   (FLG_USERELEASED, FLG_STRICTUSERELEASED,
1923                    message ("Possibly dead storage %qpassed as out parameter: %s",
1924                             sRef_unparseOpt (fref),
1925                             exprNode_unparse (fexp)),
1926                    exprNode_loc (fexp)))
1927                 {
1928                   if (sRef_isPossiblyDead (fref))
1929                     {
1930                       sRef_showStateInfo (fref);
1931                     }
1932                 }
1933               
1934               sRef_setAllocated (fref, exprNode_loc (fexp));
1935             }
1936           else if (sRef_aliasCheckSimplePred (sRef_isStateUndefined, fref) 
1937                    || sRef_aliasCheckSimplePred (sRef_isUnuseable, fref))
1938             {
1939               voptgenerror
1940                 (FLG_USEDEF,
1941                  message ("Unallocated storage %qpassed as out parameter: %s",
1942                           sRef_unparseOpt (fref),
1943                           exprNode_unparse (fexp)),
1944                  exprNode_loc (fexp));
1945
1946               sRef_setAllocated (fref, exprNode_loc (fexp));
1947             }
1948           else
1949             {
1950               ;
1951             }
1952         }
1953       
1954       (void) checkCompletelyDestroyed (fexp, fref, TRUE, FALSE,
1955                                        exprNode_loc (fexp), 0, DSC_PARAM, FALSE);
1956
1957       /* make it defined now, so checkTransfer is okay */
1958       sRef_setDefined (fref, exprNode_loc (fexp)); 
1959     }
1960   else if (uentry_isOut (arg))
1961     {
1962       DPRINTF (("Here we are!"));
1963
1964       if (ctype_isRealAP (ct)
1965           && (sRef_isStateUndefined (fref) || sRef_isUnuseable (fref)))
1966         {
1967           voptgenerror
1968             (FLG_USEDEF,
1969              message ("Unallocated storage %qpassed as out parameter to %s: %s",
1970                       sRef_unparseOpt (fref),
1971                       exprNode_unparse (fcn),
1972                       exprNode_unparse (fexp)),
1973              exprNode_loc (fexp));
1974           sRef_setAllocated (fref, exprNode_loc (fexp));
1975         }
1976       else if (sRef_isDead (fref))
1977         {
1978           if (optgenerror
1979               (FLG_USERELEASED,
1980                message ("Dead storage %qpassed as out parameter to %s: %s",
1981                         sRef_unparseOpt (fref),
1982                         exprNode_unparse (fcn),
1983                         exprNode_unparse (fexp)),
1984                exprNode_loc (fexp)))
1985             {
1986               sRef_showStateInfo (fref);
1987               sRef_setAllocated (fref, exprNode_loc (fexp));
1988             }
1989         }
1990       else if (sRef_isPossiblyDead (fref))
1991         {
1992           if (optgenerror2
1993               (FLG_USERELEASED, FLG_STRICTUSERELEASED,
1994                message ("Possibly dead storage %qpassed as out parameter to %s: %s",
1995                         sRef_unparseOpt (fref),
1996                         exprNode_unparse (fcn),
1997                         exprNode_unparse (fexp)),
1998                exprNode_loc (fexp)))
1999             {
2000               sRef_showStateInfo (fref);
2001               sRef_setAllocated (fref, exprNode_loc (fexp));
2002             }
2003         }
2004       else
2005         {
2006           ;
2007         }
2008       
2009       isOut = TRUE;
2010     }
2011   else if (uentry_isPartial (arg))
2012     {
2013       if (ctype_isRealAP (ct) 
2014           && (sRef_isStateUndefined (fref) || sRef_isUnuseable (fref)))
2015         {
2016           voptgenerror 
2017             (FLG_USEDEF,
2018              message ("Unallocated storage %qpassed as partial parameter: %s",
2019                       sRef_unparseOpt (fref),
2020                       exprNode_unparse (fexp)),
2021              exprNode_loc (fexp));
2022           sRef_setAllocated (fref, exprNode_loc (fexp));
2023         }
2024       else if (sRef_isDead (fref))
2025         {
2026           if (optgenerror
2027               (FLG_USERELEASED,
2028                message ("Dead storage %qpassed as partial parameter to %s: %s",
2029                         sRef_unparseOpt (fref),
2030                         exprNode_unparse (fcn),
2031                         exprNode_unparse (fexp)),
2032                exprNode_loc (fexp)))
2033             {
2034               sRef_showStateInfo (fref);
2035               sRef_setAllocated (fref, exprNode_loc (fexp));
2036             }
2037         }
2038       else if (sRef_isPossiblyDead (fref))
2039         {
2040           if (optgenerror2
2041               (FLG_USERELEASED, FLG_STRICTUSERELEASED,
2042                message ("Possibly dead storage %qpassed as partial parameter to %s: %s",
2043                         sRef_unparseOpt (fref),
2044                         exprNode_unparse (fcn),
2045                         exprNode_unparse (fexp)),
2046                exprNode_loc (fexp)))
2047             {
2048               sRef_showStateInfo (fref);
2049               sRef_setAllocated (fref, exprNode_loc (fexp));
2050             }
2051         }
2052       else
2053         {
2054           ;
2055         }
2056
2057       isPartial = TRUE;
2058     }
2059   else if (uentry_isStateSpecial (arg))
2060     {
2061       uentry ue = exprNode_getUentry (fcn);
2062
2063       if (ctype_isRealAP (ct) 
2064           && (sRef_isStateUndefined (fref) || sRef_isUnuseable (fref)))
2065         {
2066           voptgenerror 
2067             (FLG_USEDEF,
2068              message ("Unallocated storage %qpassed as special parameter: %s",
2069                       sRef_unparseOpt (fref),
2070                       exprNode_unparse (fexp)),
2071              exprNode_loc (fexp));
2072           sRef_setAllocated (fref, exprNode_loc (fexp));
2073         }
2074       else if (sRef_isDead (fref))
2075         {
2076           if (optgenerror
2077               (FLG_USERELEASED,
2078                message ("Dead storage %qpassed as special parameter to %s: %s",
2079                         sRef_unparseOpt (fref),
2080                         exprNode_unparse (fcn),
2081                         exprNode_unparse (fexp)),
2082                exprNode_loc (fexp)))
2083             {
2084               sRef_showStateInfo (fref);
2085               sRef_setAllocated (fref, exprNode_loc (fexp));
2086             }
2087         }
2088       else if (sRef_isPossiblyDead (fref))
2089         {
2090           if (optgenerror2
2091               (FLG_USERELEASED, FLG_STRICTUSERELEASED,
2092                message ("Possibly dead storage %qpassed as special parameter to %s: %s",
2093                         sRef_unparseOpt (fref),
2094                         exprNode_unparse (fcn),
2095                         exprNode_unparse (fexp)),
2096                exprNode_loc (fexp)))
2097             {
2098               sRef_showStateInfo (fref);
2099               sRef_setAllocated (fref, exprNode_loc (fexp));
2100             }
2101         }
2102       else
2103         {
2104           ;
2105         }
2106
2107       if (uentry_hasStateClauseList (ue))
2108         {
2109           checkPassstateClauseList (ue, fexp, fref, argno);
2110         }
2111       
2112       return; /* ??? */
2113     }
2114   else if (sRef_isStateDefined (tref))
2115     {
2116       exprNode_checkUseParam (fexp);
2117     }
2118   else
2119     {
2120       if (isSpec || (!context_getFlag (FLG_IMPOUTS)))
2121         {
2122           exprNode_checkUseParam (fexp);
2123         }
2124       else
2125         {
2126           if (!sRef_isMacroParamRef (fref) 
2127               && (ctype_isRealAP (ct)))
2128             {
2129               if (sRef_isAddress (fref))
2130                 {
2131                   if (sRef_isStateUndefined (fref) || sRef_isUnuseable (fref))
2132                     {
2133                       voptgenerror 
2134                         (FLG_USEDEF,
2135                          message 
2136                          ("Unallocated address %qpassed as implicit "
2137                           "out parameter: %s",
2138                           sRef_unparseOpt (fref),
2139                           exprNode_unparse (fexp)),
2140                          exprNode_loc (fexp));
2141                       sRef_setAllocated (fref, exprNode_loc (fexp));
2142                     }
2143                 }
2144               
2145               /* yes, I really mean this! */
2146               tref = sRef_copy (tref);
2147               sRef_setAllocated (tref, exprNode_loc (fexp)); 
2148
2149               isOut = TRUE;
2150               isImpOut = TRUE;
2151             }
2152           else 
2153             {
2154               exprNode_checkUseParam (fexp);
2155             }
2156         }
2157     }
2158
2159   if (sRef_isNew (fref))
2160     {
2161       alkind tkind = sRef_getAliasKind (tref);
2162
2163       if ((sRef_isFresh (fref) || sRef_isOnly (fref))
2164           && !alkind_isOnly (tkind) 
2165           && !alkind_isKeep (tkind) 
2166           && !alkind_isOwned (tkind)
2167           && !alkind_isError (tkind)
2168           && !uentry_isReturned (arg))
2169         
2170         {
2171           voptgenerror 
2172             (FLG_MUSTFREEFRESH,
2173              message ("New fresh storage %q(type %s) passed as %s (not released): %s",
2174                       sRef_unparseOpt (fref),
2175                       ctype_unparse (sRef_getType (fref)),
2176                       alkind_unparse (sRef_getAliasKind (tref)),
2177                       exprNode_unparse (fexp)),
2178              exprNode_loc (fexp));
2179
2180           DPRINTF (("Fresh: %s", sRef_unparseFull (fref)));
2181         }
2182       else 
2183         {
2184           if (sRef_isNewRef (fref) && !sRef_isKillRef (tref))
2185             {
2186               alkind ak = sRef_getAliasKind (tref);
2187               
2188               if (!alkind_isError (ak))
2189                 {
2190                   voptgenerror 
2191                     (FLG_MUSTFREEFRESH,
2192                      message ("New reference %q(type %s) passed as %s (not released): %s",
2193                               sRef_unparseOpt (fref),
2194                               ctype_unparse (sRef_getType (fref)),
2195                               alkind_unparse (sRef_getAliasKind (tref)),
2196                               exprNode_unparse (fexp)),
2197                      exprNode_loc (fexp));
2198                 }
2199             }
2200         }
2201     }
2202   
2203   (void) checkTransfer (fexp, exprNode_getSref (fexp),
2204                         exprNode_undefined, tref,
2205                         fcn,
2206                         exprNode_loc (fexp), TT_FCNPASS);
2207
2208   setCodePoint ();
2209   fref = exprNode_getSref (fexp);
2210   
2211   if (isOut && !sRef_isDead (fref) && !sRef_isPossiblyDead (fref))
2212     {
2213       sRef base;
2214
2215       if (ctype_isRealAP (sRef_getType (fref)))
2216         {
2217           base = sRef_makePointer (fref); 
2218         }
2219       else
2220         {
2221           base = fref;
2222         }
2223
2224       if (isImpOut)
2225         {
2226           exprNode_checkMSet (fexp, base);
2227         }
2228       else
2229         {
2230           exprNode_checkSet (fexp, base);
2231         }
2232
2233       if (sRef_isValid (base))
2234         {
2235           setCodePoint ();
2236
2237           sRef_clearDerived (base);
2238           sRef_setDefined (base, exprNode_loc (fexp));
2239           usymtab_clearAlias (base);
2240           sRef_setNullUnknown (base, exprNode_loc (fexp));
2241         }
2242     }
2243
2244   if (isPartial)
2245     {
2246       if (sRef_isValid (fref))
2247         {
2248           sRef_setPartial (fref, exprNode_loc (fexp)); 
2249         }
2250     }
2251
2252   atFunction = exprNode_undefined;
2253   atArgNo = 0;
2254   atNumArgs = 0;
2255   
2256   /* need to fixup here: derived refs could be bogus */
2257   /* (better to change sRef to not add derivs for "protected" ref) */
2258
2259   uentry_fixupSref (arg);
2260
2261   setCodePoint ();
2262
2263   DPRINTF (("Check pass: ==> %s",
2264             sRef_unparseFull (fref)));
2265 }
2266
2267 void
2268 transferChecks_globalReturn (uentry glob)
2269 {
2270   sRef_protectDerivs ();
2271   checkGlobTrans (glob, TT_GLOBRETURN);
2272   sRef_clearProtectDerivs ();
2273 }
2274
2275 void transferChecks_paramReturn (uentry actual)
2276 {
2277   checkLeaveTrans (actual, TT_PARAMRETURN);
2278 }
2279
2280 void transferChecks_loseReference (uentry actual)
2281 {
2282   checkLeaveTrans (actual, TT_LEAVETRANS);
2283 }
2284
2285 static void
2286 checkLeaveTrans (uentry actual, transferKind transferType)
2287 {
2288   sRef aref = uentry_getSref (actual);
2289   sRef origref = uentry_getOrigSref (actual);
2290
2291   if (transferType == TT_PARAMRETURN 
2292       && (sRef_isKeep (origref) || sRef_isOnly (origref)
2293           || sRef_isOwned (origref)))
2294     {
2295       /* caller cannot use, nothing to check */
2296     }
2297   else
2298     {
2299       if (sRef_isNSLocalVar (origref))
2300         {
2301           ;
2302         }
2303       else
2304         {
2305           DPRINTF (("Leave trans: %s", uentry_unparseFull (actual)));
2306
2307           (void) checkCompletelyDefined (exprNode_undefined, aref, aref,
2308                                          exprNode_undefined, origref,
2309                                          TRUE, FALSE, FALSE,
2310                                          g_currentloc, transferType,
2311                                          0, TRUE);
2312         }
2313     }
2314 }
2315
2316 static void
2317 checkGlobTrans (uentry glob, transferKind type)
2318 {
2319   sRef eref = uentry_getOrigSref (glob);
2320  
2321   DPRINTF (("Completely defined: %s", uentry_unparseFull (glob)));
2322
2323   (void) checkCompletelyDefined (exprNode_undefined, uentry_getSref (glob), 
2324                                  uentry_getSref (glob),
2325                                  exprNode_undefined, eref, 
2326                                  TRUE, FALSE, FALSE,
2327                                  g_currentloc, type, 0, TRUE);
2328 }
2329
2330 /*
2331 ** For lhs of assignment, alias kind is set from basic type.
2332 ** Yoikes!
2333 */
2334
2335 static void
2336 fixAssignLhs (sRef s)
2337 {
2338   sRef_resetStateComplete (s);
2339 }
2340
2341 static void checkStructTransfer (exprNode lhs, sRef slhs, exprNode rhs, sRef srhs,
2342                                  fileloc loc,
2343                                  transferKind tt)
2344 {
2345   ctype st = ctype_realType (sRef_getType (srhs));
2346   
2347   if (ctype_isSU (st) && ctype_isRealSU (sRef_getType (slhs))
2348       && ctype_match (sRef_getType (slhs), st))
2349     {
2350       if (tt == TT_DOASSIGN && sRef_isStateDefined (srhs))
2351         {
2352           sRef_setDefinedComplete (slhs, loc);
2353         }
2354           
2355       if (sRef_isDependent (slhs)
2356           || sRef_isObserver (slhs)
2357           || sRef_isExposed (slhs))
2358         {
2359           ;
2360         }
2361       else
2362         {
2363           if (sRef_isLocalVar (slhs)
2364               && sRef_isFileOrGlobalScope (sRef_getRootBase (srhs)))
2365             {
2366               sRef_setDependent (slhs, exprNode_loc (lhs));
2367             }
2368           else
2369             {
2370               if (ctype_isUnion (st))
2371                 {
2372                   sRef_setDefState (slhs, sRef_getDefState (srhs), 
2373                                     exprNode_loc (lhs));
2374
2375                   sRefSet_realElements (sRef_derivedFields (srhs), sr)
2376                     {
2377                       if (sRef_isField (sr))
2378                         {
2379                           cstring fieldname = sRef_getField (sr);
2380                           sRef lfld = sRef_makeField (slhs, fieldname);
2381
2382                           (void) checkTransfer (rhs, sr, lhs, lfld, 
2383                                                 exprNode_undefined,
2384                                                 exprNode_loc (lhs), tt);
2385                         }
2386                     } end_sRefSet_realElements ;
2387                 }
2388               else
2389                 {
2390                   uentryList fields = ctype_getFields (st);
2391                   
2392                   uentryList_elements (fields, field)
2393                     {
2394                       sRef rfld = sRef_makeField (srhs, uentry_rawName (field));
2395                       sRef lfld = sRef_makeField (slhs, uentry_rawName (field));
2396                       (void) checkTransfer (rhs, rfld, lhs, lfld, 
2397                                             exprNode_undefined,
2398                                             exprNode_loc (lhs), tt);
2399                     } end_uentryList_elements ;
2400                 }
2401
2402               if (sRef_isOnly (srhs))
2403                 {
2404                   sRef_setKeptComplete (srhs, loc);
2405                 }
2406             }
2407         }
2408     }
2409 }
2410
2411 void
2412 transferChecks_initialization (exprNode lhs, exprNode rhs)
2413 {
2414   sRef slhs = exprNode_getSref (lhs);
2415   
2416   if (sRef_isFileOrGlobalScope (slhs) || (!sRef_isCvar (slhs)))
2417     {
2418       (void) checkTransfer (rhs, exprNode_getSref (rhs), 
2419                             lhs, slhs, 
2420                             exprNode_undefined,
2421                             exprNode_loc (rhs), TT_GLOBINIT);
2422     }
2423   else
2424     {
2425       transferChecks_assign (lhs, rhs);
2426     }
2427 }
2428
2429 void
2430 transferChecks_assign (exprNode lhs, exprNode rhs)
2431 {
2432   sRef slhs = exprNode_getSref (lhs);
2433   sRef srhs = exprNode_getSref (rhs);
2434   sRef base = sRef_getBaseSafe (slhs);
2435   nstate ns;
2436   
2437   DPRINTF (("Check assign: %s = %s", exprNode_unparse (lhs),
2438             exprNode_unparse (rhs)));
2439   DPRINTF (("lhs: %s", sRef_unparseFull (slhs)));
2440   DPRINTF (("rhs: %s", sRef_unparseFull (srhs)));
2441
2442   if (ctype_isRealSU (sRef_getType (srhs)))
2443     {
2444       checkStructTransfer (lhs, slhs, rhs, srhs, exprNode_loc (lhs), TT_FIELDASSIGN);
2445     }
2446   else
2447     {
2448       DPRINTF (("lhs: %s", sRef_unparseFull (slhs)));
2449       DPRINTF (("rhs: %s", sRef_unparseFull (srhs)));
2450       (void) checkTransfer (rhs, srhs, lhs, slhs, 
2451                             exprNode_undefined,
2452                             exprNode_loc (lhs), TT_DOASSIGN);
2453       DPRINTF (("lhs: %s", sRef_unparseFull (slhs)));
2454       DPRINTF (("rhs: %s", sRef_unparseFull (srhs)));
2455     }
2456
2457   if (sRef_isConst (srhs) && sRef_isLocalState (srhs))
2458     {
2459       /* constants can match anything (e.g., NULL) */
2460       sRef_setAliasKind (slhs, AK_ERROR, fileloc_undefined);
2461     }
2462
2463   if (sRef_isValid (base) && sRef_isStateDefined (base))
2464     {
2465       sRef_setPdefined (base, g_currentloc); 
2466     }
2467
2468   if (sRef_isPartial (srhs))
2469     {
2470       sRef_setPartial (slhs, exprNode_loc (rhs));
2471     }
2472
2473   ns = sRef_getNullState (srhs);
2474
2475   if (nstate_possiblyNull (ns))
2476     {
2477       if (usymtab_isGuarded (srhs))
2478         {
2479           ns = NS_NOTNULL;
2480         }
2481     }
2482
2483   sRef_setNullStateInnerComplete (slhs, ns, exprNode_loc (rhs));
2484
2485   if (sRef_isExposed (srhs) || sRef_isObserver (srhs))
2486     {
2487       sRef_setExKind (slhs, sRef_getExKind (srhs), exprNode_loc (rhs));
2488     }
2489   
2490   DPRINTF (("Done transfer: %s", sRef_unparseFull (slhs)));
2491 }
2492
2493 static void
2494 checkTransferNullAux (sRef fref, exprNode fexp, /*@unused@*/ bool ffix,
2495                       sRef tref, exprNode texp, /*@unused@*/ bool tfix,
2496                       fileloc loc, transferKind transferType)
2497 {
2498   alkind tkind = sRef_getAliasKind (tref);
2499   ctype ttyp = ctype_realType (sRef_getType (tref));
2500
2501   if (ctype_isUnknown (ttyp))
2502     {
2503       ttyp = exprNode_getType (texp);
2504       
2505       if (ctype_isUnknown (ttyp))
2506         {
2507           ttyp = exprNode_getType (fexp);
2508
2509           if (ctype_isUnknown (ttyp))
2510             {
2511               ttyp = sRef_getType (fref);
2512             }
2513         }
2514     }
2515
2516   if (ctype_isFunction (ttyp) && (transferType == TT_FCNRETURN))
2517     {
2518       ttyp = ctype_getReturnType (ttyp);
2519     }
2520
2521   /*
2522   ** check for null (don't need to check aliases??)
2523   */
2524
2525   if (sRef_possiblyNull (fref) 
2526       && !usymtab_isGuarded (fref) 
2527       && ctype_isRealAP (ttyp))
2528     {
2529       if (!alkind_isLocal (tkind) && !alkind_isFresh (tkind)
2530           && !sRef_perhapsNull (tref)
2531           && !(transferType == TT_DOASSIGN))
2532         {
2533           if (transferType == TT_GLOBINIT)
2534             {
2535               if (sRef_isNotNull (tref))
2536                 {
2537                   if (optgenerror
2538                       (FLG_SYNTAX, /*@i432 kuldge flag... */
2539                        message ("%s %q initialized to %s value: %q",
2540                                 sRef_getScopeName (tref),
2541                                 sRef_unparse (tref),
2542                                 sRef_nullMessage (fref),
2543                                 generateText (fexp, texp, tref, transferType)),
2544                        loc))
2545                     {
2546                       sRef_showNullInfo (fref);
2547                       sRef_setNullError (tref);
2548                     }
2549                 }
2550               else
2551                 {
2552                   if (optgenerror
2553                       (FLG_NULLASSIGN,
2554                        message ("%s %q initialized to %s value: %q",
2555                                 sRef_getScopeName (tref),
2556                                 sRef_unparse (tref),
2557                                 sRef_nullMessage (fref),
2558                                 generateText (fexp, texp, tref, transferType)),
2559                        loc))
2560                     {
2561                       sRef_showNullInfo (fref);
2562                       sRef_setNullError (tref);
2563                     }
2564                 }
2565             }
2566           else
2567             {
2568               if (optgenerror
2569                   ((transferType == TT_FCNPASS) ? FLG_NULLPASS : FLG_NULLRET,
2570                    message ("%q storage %q%s: %q",
2571                             cstring_capitalize (sRef_nullMessage (fref)),
2572                             sRef_unparseOpt (fref),
2573                             transferNullMessage (transferType), 
2574                             generateText (fexp, texp, tref, transferType)),
2575                    loc))
2576                 {
2577                   sRef_showNullInfo (fref);
2578                   sRef_setNullError (fref);
2579                 }
2580             }
2581         }
2582       else
2583         {
2584           ;
2585         }
2586     }  
2587 }
2588
2589
2590 static void
2591 checkTransferAssignAux (sRef fref, exprNode fexp, /*@unused@*/ bool ffix,
2592                         /*@exposed@*/ sRef tref, exprNode texp, bool tfix,
2593                         fileloc loc, transferKind transferType)
2594 {
2595   alkind tkind = sRef_getAliasKind (tref);
2596
2597   /*
2598   ** Assignment to same --- no errors, or state changes.
2599   ** This can happen when returned params are used.
2600   */
2601
2602   if (sRef_sameName (fref, tref))
2603     {
2604       sRef_copyState (tref, fref); 
2605       return;
2606     }
2607   
2608   if ((alkind_isOnly (tkind) || alkind_isFresh (tkind) 
2609        || alkind_isNewRef (tkind) || alkind_isOwned (tkind))
2610       && !(sRef_isDead (tref) 
2611            || sRef_isStateUndefined (tref) 
2612            || sRef_isUnuseable (tref) 
2613            || sRef_isPartial (tref)
2614            || sRef_definitelyNull (tref) 
2615            || sRef_isStackAllocated (tref) 
2616            || sRef_isAllocIndexRef (tref))
2617       && !(sRef_same (fref, tref)) /* okay to assign to self (returned params) */
2618       && !(usymtab_isDefinitelyNull (tref))) 
2619     {
2620       if (transferChecks_canLoseReference (tref, loc))
2621         {
2622           ; /* no error */
2623         }
2624       else
2625         {
2626           flagcode flg = sRef_isFresh (tref) ? FLG_MUSTFREEFRESH : FLG_MUSTFREEONLY;
2627
2628           if (sRef_hasLastReference (tref))
2629             {
2630               if (optgenerror 
2631                   (flg,
2632                    message ("Last reference %q to %s storage %q(type %s) not released "
2633                             "before assignment: %q",
2634                             sRef_unparse (tref),
2635                             alkind_unparse (tkind),
2636                             sRef_unparseOpt (sRef_getAliasInfoRef (tref)),
2637                             ctype_unparse (sRef_getType (tref)),
2638                             generateText (fexp, texp, tref, transferType)),
2639                    loc))
2640                 {
2641                   sRef_showRefLost (tref);
2642                 }
2643             }
2644           else
2645             {
2646               if (context_inGlobalScope ())
2647                 {
2648                   /* no errors for static initializations */
2649                 }
2650               else 
2651                 {
2652                   /*
2653                   ** don't report this error for a[i], since it could
2654                   ** be a new element.
2655                   */
2656                   
2657                   if (alkind_isNewRef (tkind))
2658                     {
2659                       if (optgenerror 
2660                           (flg,
2661                            message 
2662                            ("%q %q(type %s) not released before assignment: %q",
2663                             cstring_makeLiteral
2664                             (alkind_isKillRef (sRef_getOrigAliasKind (tref))
2665                              ? "Kill reference parameter" : "New reference"),
2666                             sRef_unparseOpt (tref),
2667                             ctype_unparse (sRef_getType (tref)),
2668                             generateText (fexp, texp, tref, transferType)),
2669                            loc))
2670                         {
2671                           sRef_showAliasInfo (tref);
2672                           sRef_setAliasKind (tref, AK_ERROR, loc);
2673                         }
2674                     }
2675                   else if
2676                     (!(sRef_isUnknownArrayFetch (tref)
2677                        && !context_getFlag (FLG_STRICTDESTROY))
2678                      && !sRef_isUnionField (tref)
2679                      && !sRef_isRelDef (tref)
2680                      && optgenerror 
2681                      (flg,
2682                       message 
2683                       ("%s storage %q(type %s) not released before assignment: %q",
2684                        alkind_capName (tkind),
2685                        sRef_unparseOpt (tref),
2686                        ctype_unparse (sRef_getType (tref)),
2687                        generateText (fexp, texp, tref, transferType)),
2688                       loc))
2689                     {
2690                       sRef_showAliasInfo (tref);
2691                     }
2692                   else
2693                     {
2694                       ;
2695                     }
2696                 }
2697             }
2698         }
2699     }
2700
2701   fixAssignLhs (tref);
2702
2703   if (sRef_isRefCounted (tref)) /* tkind might not be correct now */
2704     {
2705       if (sRef_isNewRef (fref))
2706         {
2707           sRef_setAliasKind (tref, AK_NEWREF, loc);
2708         }
2709       else if (sRef_isConst (fref))
2710         {
2711           /* for now, constants are not ref counted */
2712           sRef_setAliasKind (tref, AK_ERROR, loc);
2713         }
2714       else
2715         {
2716           ;
2717         }
2718
2719       if (!sRef_isNSLocalVar (tref) 
2720           && sRef_isRefCounted (fref)
2721           && sRef_isStateDefined (fref))
2722         {
2723           voptgenerror 
2724             (FLG_NEWREFTRANS,
2725              message ("New reference %qto reference counted storage: %q",
2726                       sRef_unparseOpt (tref),
2727                       generateText (fexp, texp, tref, transferType)),
2728              loc);
2729         }
2730     }
2731
2732   /*
2733   ** Not for structures and unions, since assignments copy.
2734   */
2735
2736   if (sRef_isStack (fref)
2737       && !ctype_isSU (ctype_realType (sRef_getType (fref))))
2738     {
2739       sRef_setAliasKindComplete (tref, AK_STACK, loc);
2740     }
2741
2742   if (sRef_isNSLocalVar (tref) 
2743       && !sRef_isOwned (tref) /*< should only apply to static >*/
2744       && ctype_isMutable (sRef_getType (tref)))
2745     {
2746       if (sRef_isOnly (fref) && sRef_isNew (fref)) 
2747         {
2748           if (!tfix) 
2749             {
2750               sRef_setFresh (tref, loc);
2751             }
2752         }
2753     }
2754 }
2755
2756 /*
2757 ** requires sRef_isOnly (fref)
2758 */
2759
2760 static void
2761 checkOnlyTransferAux (sRef fref, exprNode fexp, bool ffix,
2762                       sRef tref, exprNode texp, /*@unused@*/ bool tfix,
2763                       fileloc loc, transferKind transferType)
2764 {     
2765   alkind tkind = sRef_getAliasKind (tref);
2766
2767   if (sRef_isExposed (tref) || sRef_isObserver (tref))
2768     {
2769       if (transferType == TT_FCNRETURN && sRef_isNew (fref)
2770           && !alkind_isError (tkind))
2771         {
2772           if (optgenerror 
2773               (FLG_ONLYTRANS,
2774                message ("Only storage %q%q (will not be released): %q",
2775                         sRef_unparseOpt (fref),
2776                         transferErrorMessage (transferType, tkind),
2777                         generateText (fexp, texp, tref, transferType)),
2778                loc))
2779             {
2780               sRef_showAliasInfo (fref);
2781             }
2782         }
2783       
2784       /* no errors for exposed transfers (is this good enough?) */
2785     }
2786   else if (alkind_isOnly (tkind) || alkind_isKeep (tkind) || alkind_isOwned (tkind))
2787     {
2788       ; /* okay */
2789     }
2790   else if ((transferType == TT_FCNPASS)
2791            && (alkind_isUnknown (tkind) 
2792                || alkind_isTemp (tkind) || alkind_isUnique (tkind)))
2793     {
2794       if (sRef_isFresh (fref) 
2795           && alkind_isUnknown (tkind) && !context_getFlag (FLG_PASSUNKNOWN))
2796         {
2797           if (!ffix) sRef_setAliasKind (fref, AK_UNKNOWN, loc); 
2798         }
2799     }
2800   else if (alkind_isLocal (tkind) 
2801            || alkind_isFresh (tkind) || alkind_isUnknown (tkind))
2802     {
2803       if ((transferType == TT_DOASSIGN)
2804           && sRef_isNew (fref) 
2805           && sRef_isOnly (fref))
2806         {
2807           bool error = FALSE;
2808
2809           if (alkind_isUnknown (tkind)
2810               && sRef_isFileOrGlobalScope (sRef_getRootBase (tref)))
2811             {
2812               if (optgenerror 
2813                   (FLG_ONLYUNQGLOBALTRANS,
2814                    message ("Only storage %q%q: %q",
2815                             sRef_unparseOpt (fref),
2816                             transferErrorMessage (transferType, tkind),
2817                             generateText (fexp, texp, tref, transferType)),
2818                    loc))
2819                 {
2820                   sRef_showAliasInfo (fref);
2821                   sRef_setAliasKind (tref, AK_ERROR, loc);
2822                   error = TRUE;
2823                 }
2824             }
2825
2826           if (!error && !ffix) 
2827             {
2828               sRef_setFresh (tref, loc);
2829             }
2830         }
2831       else
2832         {
2833           if (alkind_isLocal (tkind))
2834             {
2835               if (sRef_sameName (tref, fref))
2836                 {
2837                   ; /* don't set this --- corresponds to return transfer */
2838                 }
2839               else
2840                 {
2841                   /*
2842                   ** Don't set local to dependent.  Error will
2843                   ** be detected through aliasing.  Except for
2844                   ** arrays.
2845                   */
2846                   
2847                   if (!tfix && sRef_isThroughArrayFetch (fref)
2848                       && context_getFlag (FLG_DEPARRAYS))
2849                     {
2850                       sRef_setDependent (tref, loc);
2851                     }
2852                 }
2853             }
2854           else
2855             {
2856               if (optgenerror 
2857                   (FLG_ONLYTRANS,
2858                    message ("Only storage %q%q: %q",
2859                             sRef_unparseOpt (fref),
2860                             transferErrorMessage (transferType, tkind),
2861                             generateText (fexp, texp, tref, transferType)),
2862                    loc))
2863                 {
2864                   sRef_showAliasInfo (fref);
2865                 }
2866             }
2867         }
2868     }
2869   else
2870     {
2871       if (alkind_isError (tkind) 
2872           || (alkind_isUnknown (tkind) && !context_getFlag (FLG_MEMIMPLICIT)))
2873         {
2874           flagcode_recordSuppressed (FLG_ONLYTRANS);
2875         }
2876       else
2877         {
2878           if ((alkind_isKept (tkind) || alkind_isStack (tkind) 
2879                || alkind_isDependent (tkind))
2880               && sRef_isNSLocalVar (tref))
2881             {
2882               ; /* okay */
2883             }
2884           else
2885             {
2886               if (optgenerror 
2887                   (FLG_ONLYTRANS,
2888                    message ("Only storage %q%q: %q",
2889                             sRef_unparseOpt (fref),
2890                             transferErrorMessage (transferType, tkind),
2891                             generateText (fexp, texp, tref, transferType)),
2892                    loc))
2893                 {
2894                   sRef_showAliasInfo (fref);
2895                   
2896                   if (transferType == TT_DOASSIGN)
2897                     {
2898                       /*
2899                       ** alias kind unknown to suppress future messages
2900                       */
2901                       
2902                       if (!ffix && sRef_isNSLocalVar (sRef_getRootBase (fref)))
2903                         {
2904                           sRef_clearAliasKind (fref);
2905                         }
2906                     }
2907                 }
2908             }
2909         }
2910     }
2911 }
2912
2913 /*
2914 ** ??? same as checkOnly ?
2915 */
2916
2917 static void
2918 checkOwnedTransferAux (sRef fref, exprNode fexp, bool ffix,
2919                        sRef tref, exprNode texp, bool tfix,
2920                        fileloc loc, transferKind transferType)
2921 {     
2922   alkind tkind = sRef_getAliasKind (tref);
2923
2924   if (sRef_isExposed (tref) || sRef_isObserver (tref))
2925     {
2926       if (transferType == TT_FCNRETURN && sRef_isNew (fref))
2927         {
2928           if (optgenerror 
2929               (FLG_OWNEDTRANS,
2930                message ("Owned storage %q%q (will not be released): %q",
2931                         sRef_unparseOpt (fref),
2932                         transferErrorMessage (transferType, tkind),
2933                         generateText (fexp, texp, tref, transferType)),
2934                loc))
2935             {
2936               sRef_showAliasInfo (fref);
2937             }
2938         }
2939     }
2940   else if (alkind_isOnly (tkind) || alkind_isKeep (tkind) 
2941            || alkind_isDependent (tkind)
2942            || alkind_isOwned (tkind))
2943     {
2944       /* okay */
2945     }
2946   else if (alkind_isLocal (tkind)
2947            || alkind_isFresh (tkind) || alkind_isUnknown (tkind))
2948     {
2949       if ((transferType == TT_DOASSIGN)
2950           && sRef_isNew (fref) && sRef_isOnly (fref))
2951         {
2952           if (!tfix) 
2953             { 
2954               sRef_setFresh (tref, loc); 
2955             }
2956         }
2957       else
2958         {
2959         }
2960     }
2961   else if ((transferType == TT_FCNPASS)
2962            && (alkind_isUnknown (tkind) 
2963                || alkind_isTemp (tkind) || alkind_isUnique (tkind)))
2964     {
2965       if (sRef_isFresh (fref) 
2966           && alkind_isUnknown (tkind) && !context_getFlag (FLG_PASSUNKNOWN))
2967         {
2968           if (!ffix) { sRef_clearAliasKind (fref); }
2969         }
2970     }
2971   else
2972     {
2973       if (alkind_isUnknown (tkind) && !context_getFlag (FLG_MEMIMPLICIT))
2974         {
2975           flagcode_recordSuppressed (FLG_OWNEDTRANS);
2976         }
2977       else
2978         {
2979           if (alkind_isKept (tkind) && sRef_isNSLocalVar (tref))
2980             {
2981               ; /* okay */
2982             }
2983           else
2984             {
2985               voptgenerror
2986                 (FLG_OWNEDTRANS,
2987                  message ("Owned storage %q%q: %q",
2988                           sRef_unparseOpt (fref),
2989                           transferErrorMessage (transferType, tkind),
2990                           generateText (fexp, texp, tref, transferType)),
2991                  loc);
2992             }
2993         }
2994       
2995       if (transferType == TT_DOASSIGN)
2996         {
2997           /*
2998            ** alias kind unknown to suppress future messages
2999            */
3000           
3001           if (!ffix) { sRef_clearAliasKind (fref); }
3002         }
3003     }
3004 }
3005   
3006 static void
3007 checkFreshTransferAux (sRef fref, exprNode fexp, bool ffix,
3008                        sRef tref, exprNode texp, /*@unused@*/ bool tfix,
3009                        fileloc loc, transferKind transferType)
3010 {     
3011   alkind tkind = sRef_getAliasKind (tref);
3012
3013   /*
3014   ** error to return fresh as non-only
3015   */
3016
3017   if (transferType == TT_FCNRETURN
3018       && !(alkind_isOnly (tkind) || alkind_isNewRef (tkind)))
3019     {
3020       if (alkind_isUnknown (tkind) && !context_getFlag (FLG_MEMIMPLICIT))
3021         {
3022           flagcode_recordSuppressed (FLG_NEWREFTRANS);
3023         }
3024       else
3025         {
3026           if (alkind_isError (tkind))
3027             {
3028               if (!ffix) 
3029                 { 
3030                   sRef_killComplete (fref, loc); 
3031                 }
3032             }
3033           else if (alkind_isRefCounted (tkind))
3034             {
3035               if (optgenerror 
3036                   (FLG_NEWREFTRANS,
3037                    message
3038                    ("New reference returned without newref qualifier: %q",
3039                     generateText (fexp, texp, tref, transferType)),
3040                    loc))
3041                 {
3042                   sRef_showAliasInfo (fref);
3043                   sRef_killComplete (fref, loc);
3044                 }
3045               }
3046           else 
3047             {
3048               if (optgenerror 
3049                   (FLG_FRESHTRANS,
3050                    message ("Fresh storage %q (should be only): %q",
3051                             transferErrorMessage (transferType, tkind),
3052                             generateText (fexp, texp, tref, transferType)),
3053                    loc))
3054                 {
3055                   sRef_showAliasInfo (fref);
3056                   sRef_killComplete (fref, loc);
3057                 }
3058             }
3059         }
3060     }
3061   
3062   /*
3063   ** Okay to assign fresh to only, shared or unqualified.
3064   ** 
3065   ** should generate other errors? 
3066   */
3067
3068   if (alkind_isOnly (tkind))
3069     {
3070       if (transferType == TT_DOASSIGN && !sRef_isFileOrGlobalScope (tref))
3071         {
3072           if (!ffix) 
3073             { 
3074               if (!sRef_isNSLocalVar (tref))
3075                 {
3076                   sRef_setKeptComplete (fref, loc); 
3077                 }
3078             }
3079         }
3080       else
3081         {
3082           if (sRef_isConst (fref))
3083             {
3084               ;
3085             }
3086           else
3087             {
3088               if (!ffix) 
3089                 { 
3090                   sRef_killComplete (fref, loc); 
3091                 }
3092             }
3093         }
3094     }
3095   else if (alkind_isOwned (tkind))
3096     {
3097       if (!ffix) 
3098         { 
3099           sRef_setDependentComplete (fref, loc); 
3100         }
3101     }
3102   else if (alkind_isRefCounted (tkind)
3103            && (transferType == TT_FCNRETURN) && sRef_isFresh (fref))
3104     {
3105       if (!ffix) 
3106         { 
3107           sRef_killComplete (fref, loc); 
3108         }
3109     }
3110   else if (alkind_isKeep (tkind))
3111     {
3112       if (!ffix) 
3113         { 
3114           if (!sRef_isNSLocalVar (tref))
3115             {
3116               sRef_setKeptComplete (fref, loc); 
3117             }
3118         }
3119     }
3120   else if (alkind_isShared (tkind))
3121     {
3122       if (!ffix) { sRef_setShared (fref, loc); }
3123     }
3124   else if (alkind_isLocal (tkind) || alkind_isUnknown (tkind))
3125     {
3126       if (transferType == TT_DOASSIGN || transferType == TT_FCNRETURN)
3127         {
3128           /*
3129           ** local shares fresh.  Make it owned/dependent. 
3130           */
3131
3132           if (!tfix) 
3133             { 
3134               sRef_setOwned (tref, loc); 
3135             }
3136
3137           if (!ffix && !tfix) 
3138             { 
3139               sRef_setDependentComplete (fref, loc); 
3140             }
3141
3142           /* NO! sRef_clearAliasKind (fref); */
3143         }
3144       else 
3145         {
3146           if (context_getFlag (FLG_PASSUNKNOWN))
3147             {
3148               sRef_clearAliasKind (fref);
3149             }
3150         }
3151     }
3152   else
3153     {
3154       ;
3155     }
3156 }
3157
3158 static void
3159 checkTransferExposure (sRef fref, exprNode fexp, /*@unused@*/ bool ffix,
3160                        sRef tref, exprNode texp, bool tfix,
3161                        fileloc loc, 
3162                        transferKind transferType)
3163 {
3164   alkind fkind = sRef_getAliasKind (fref);
3165   alkind tkind = sRef_getAliasKind (tref);
3166   exkind tekind = sRef_getExKind (tref);
3167
3168   if (sRef_isObserver (fref) && ctype_isMutable (sRef_getType (fref)))
3169     {
3170       /*
3171       ** observer -> exposed or observer
3172       */
3173       
3174       /*
3175       ** observer -> temp is okay [NO!  really? only in function calls]
3176       */
3177
3178       if (sRef_isExposed (tref) || sRef_isObserver (tref)
3179           || alkind_isLocal (tkind))
3180         {
3181           /* okay */
3182           
3183           if ((transferType == TT_DOASSIGN) && alkind_isLocal (tkind))
3184             {
3185               if (!tfix) 
3186                 {
3187                   sRef_setAliasKindComplete (tref, fkind, loc); 
3188                 }
3189             }
3190         }
3191       else
3192         {
3193           if (transferType == TT_FCNRETURN 
3194               || transferType == TT_DOASSIGN
3195               || transferType == TT_FIELDASSIGN
3196               || transferType == TT_GLOBINIT)
3197             {
3198               bool hasError = FALSE;
3199               
3200               if (exprNode_isStringLiteral (fexp)
3201                   && transferType == TT_GLOBINIT)
3202                 {
3203                   hasError = optgenerror
3204                     (FLG_READONLYTRANS,
3205                      message ("Read-only string literal storage %q%q: %q",
3206                               sRef_unparseOpt (fref),
3207                               transferErrorExpMessage (transferType, tekind),
3208                               generateText (fexp, texp, tref, transferType)),
3209                      loc);
3210
3211                   sRef_setAliasKind (fref, AK_ERROR, fileloc_undefined);
3212                 }
3213               else 
3214                 {
3215                   if ((transferType == TT_DOASSIGN
3216                        || transferType == TT_FIELDASSIGN)
3217                       && (sRef_isNSLocalVar (tref)
3218                           || (exprNode_isStringLiteral (fexp)
3219                               && ctype_isRealArray (exprNode_getType (texp)))))
3220                     {
3221                       ; /* No error for local assignment or assignment
3222                            to static array (copies string). */
3223                     }
3224                   else
3225                     {
3226                       if (exprNode_isStringLiteral (fexp))
3227                         {
3228                           hasError = optgenerror 
3229                             (FLG_READONLYTRANS,
3230                              message
3231                              ("Read-only string literal storage %q%q: %q",
3232                               sRef_unparseOpt (fref),
3233                               transferErrorExpMessage (transferType, tekind),
3234                               generateText (fexp, texp, tref, transferType)),
3235                              loc);
3236                           
3237                         }
3238
3239                       if (!hasError)
3240                         {
3241                           hasError = optgenerror 
3242                             (FLG_OBSERVERTRANS,
3243                              message
3244                              ("Observer storage %q%q: %q",
3245                               sRef_unparseOpt (fref),
3246                               transferErrorExpMessage (transferType, tekind),
3247                               generateText (fexp, texp, tref, transferType)),
3248                              loc);
3249                         }
3250                     }
3251                 }
3252               
3253               if (hasError)
3254                 {
3255                   if (transferType != TT_GLOBINIT)
3256                     {
3257                       sRef_showExpInfo (fref);
3258                       sRef_setAliasKind (tref, AK_ERROR, loc);
3259                     }
3260                 }
3261               else 
3262                 {
3263                   if (transferType == TT_DOASSIGN && !tfix)
3264                     {
3265                       DPRINTF (("Setting unknown!"));
3266                       /* sRef_setAliasKind (tref, AK_ERROR, loc); */
3267                     }
3268                 }
3269             }
3270           else /* TT_FCNPASS */
3271             {
3272               llassert (transferType == TT_FCNPASS);
3273
3274               if (alkind_isTemp (tkind) 
3275                   || alkind_isDependent (tkind)
3276                   || alkind_isRefCounted (tkind))
3277                 {
3278                   ; /* okay */
3279                 }
3280               else 
3281                 {
3282                   if (!alkind_isError (tkind))
3283                     {
3284                       if (optgenerror 
3285                           (FLG_OBSERVERTRANS,
3286                            message ("Observer storage %q%q: %q",
3287                                     sRef_unparseOpt (fref),
3288                                     transferErrorMessage (transferType, tkind),
3289                                     generateText (fexp, texp, tref, transferType)),
3290                            loc))
3291                         {
3292                           sRef_showExpInfo (fref);
3293                           sRef_clearAliasState (fref, loc); 
3294                         }
3295                     }
3296                 }
3297             }
3298         }
3299     }
3300   else if (sRef_isExposed (fref) && ctype_isMutable (sRef_getType (fref)))
3301     {
3302       if (transferType == TT_FCNRETURN)
3303         {
3304           if (!(sRef_isExposed (tref) || sRef_isObserver (tref)
3305                 || sRef_isParam (fref)))
3306             {
3307               if (optgenerror
3308                   (FLG_EXPOSETRANS,
3309                    message ("Exposed storage %q%q: %q",
3310                             sRef_unparseOpt (fref),
3311                             transferErrorExpMessage (transferType, tekind),
3312                             generateText (fexp, texp, tref, transferType)),
3313                    loc))
3314                 {
3315                   sRef_showExpInfo (fref);
3316                 }
3317             }
3318         }
3319       else if (transferType == TT_FCNPASS)
3320         {
3321           if (!(sRef_isExposed (tref) 
3322                 || sRef_isObserver (tref)
3323                 || (alkind_isUnknown (tkind) 
3324                     || alkind_isDependent (tkind)
3325                     || alkind_isTemp (tkind)
3326                     || alkind_isKillRef (tkind)
3327                     || alkind_isRefCounted (tkind))))
3328             {
3329               if (alkind_isUnique (tkind) || alkind_isError (tkind))
3330                 {
3331                 }
3332               else 
3333                 {
3334                   if (optgenerror 
3335                       (FLG_EXPOSETRANS,
3336                        message ("Exposed storage %q%q: %q",
3337                                 sRef_unparseOpt (fref),
3338                                 transferErrorMessage (transferType, tkind),
3339                                 generateText (fexp, texp, tref, transferType)),
3340                        loc))
3341                     {
3342                       sRef_showExpInfo (fref);
3343                       sRef_clearAliasState (fref, loc); 
3344                     }
3345                 }
3346
3347             }
3348           else
3349             {
3350               ;
3351             }
3352         }
3353       else if (transferType == TT_DOASSIGN
3354                /* evans 2001-10-05: added TT_FIELDASSIGN: */
3355                || transferType == TT_FIELDASSIGN)
3356         {
3357           if (!(sRef_isExposed (tref) 
3358                 || !sRef_isCvar (tref)
3359                 || (alkind_isUnknown (tkind)
3360                     || alkind_isDependent (tkind)
3361                     || alkind_isRefCounted (tkind) 
3362                     || alkind_isNewRef (tkind)
3363                     || alkind_isFresh (tkind)
3364                     || alkind_isLocal (tkind))))
3365             {
3366               if (optgenerror 
3367                   (FLG_EXPOSETRANS,
3368                    message ("Exposed storage %q%q: %q",
3369                             sRef_unparseOpt (fref),
3370                             transferErrorExpMessage (transferType, tekind),
3371                             generateText (fexp, texp, tref, transferType)),
3372                    loc))
3373                 {
3374                   sRef_showExpInfo (fref);
3375                 }
3376             }
3377           if (!tfix) { sRef_setExposed (tref, loc); }
3378         }
3379       else
3380         {
3381           llassert (transferType == TT_GLOBPASS
3382                     || transferType == TT_GLOBRETURN
3383                     || transferType == TT_PARAMRETURN
3384                     || transferType == TT_LEAVETRANS
3385                     || transferType == TT_GLOBINIT);
3386         }
3387     }
3388   else
3389     {
3390       ;
3391     }
3392 }
3393
3394 /*
3395 ** returns TRUE if there is no error reported
3396 **
3397 ** if fixt, don't change tref (except if error reported.)
3398 ** if fixf, don't change fref (except if error reported.)
3399 */
3400
3401 static void
3402 checkTransferAux (exprNode fexp, /*@exposed@*/ sRef fref, bool ffix,
3403                   exprNode texp, /*@exposed@*/ sRef tref, bool tfix,
3404                   fileloc loc, transferKind transferType)
3405 {
3406   alkind fkind;
3407   alkind tkind;
3408   bool isassign = (transferType == TT_DOASSIGN);
3409   bool isfieldassign = (transferType == TT_FIELDASSIGN);
3410   bool iseitherassign = isassign || (transferType == TT_FIELDASSIGN);
3411   bool isfcnpass = (transferType == TT_FCNPASS);
3412   bool isfcnreturn = (transferType == TT_FCNRETURN);
3413
3414   setCodePoint ();
3415
3416   if (!ffix && !tfix)
3417     {
3418       setCodePoint ();
3419       checkTransferNullAux (fref, fexp, ffix, tref, texp, tfix, 
3420                             loc, transferType);
3421     }
3422
3423   if (isassign)
3424     {
3425       setCodePoint ();
3426       checkTransferAssignAux (fref, fexp, ffix, tref, texp, tfix,
3427                               loc, transferType);
3428     }
3429
3430   /*
3431   ** Check for definition 
3432   */
3433
3434   /*
3435   ** errors passing out params already detected in checkAnyCall
3436   */
3437
3438   if (!ffix && !tfix)
3439     {
3440       bool defok = TRUE;
3441
3442       if (!iseitherassign 
3443           || (!sRef_isNSLocalVar (tref) 
3444               && (sRef_isAnyDefined (tref) || !sRef_stateKnown (tref))))
3445         {
3446           setCodePoint ();
3447
3448           if (!ynm_toBoolRelaxed 
3449               (checkCompletelyDefined (fexp, fref, fref,
3450                                        texp, tref,
3451                                        TRUE, FALSE, FALSE, 
3452                                        loc, transferType, 0, TRUE)))
3453             {
3454               defok = FALSE;
3455             }
3456         }
3457
3458       setCodePoint ();
3459       
3460       if (defok && iseitherassign)
3461         {
3462           sRef_setDefState (tref, sRef_getDefState (fref), loc);
3463         }
3464     }
3465
3466   /*
3467   ** check exposure
3468   */
3469
3470   setCodePoint ();
3471   checkTransferExposure (fref, fexp, ffix, tref, texp, tfix, 
3472                          loc, transferType);
3473
3474   fkind = sRef_getAliasKind (fref);
3475   tkind = sRef_getAliasKind (tref);
3476
3477   /*
3478   ** check aliasing
3479   */
3480
3481   if (alkind_isOnly (fkind))
3482     {
3483       setCodePoint ();
3484       checkOnlyTransferAux (fref, fexp, ffix,
3485                             tref, texp, tfix, 
3486                             loc, transferType);
3487     }
3488   else if (alkind_isFresh (fkind))
3489     {
3490       setCodePoint ();
3491       checkFreshTransferAux (fref, fexp, ffix,
3492                              tref, texp, tfix,
3493                              loc, transferType);
3494     }
3495   else if (alkind_isOwned (fkind))
3496     {
3497       setCodePoint ();
3498       checkOwnedTransferAux (fref, fexp, ffix,
3499                              tref, texp, tfix,
3500                              loc, transferType);
3501     }
3502   else if (alkind_isDependent (fkind))
3503     {
3504       setCodePoint ();
3505       if (isfcnreturn && 
3506           (sRef_isExposed (tref) || sRef_isObserver (tref)))
3507         {
3508           ; /* okay */
3509         }
3510       else if ((alkind_isOnly (tkind) || alkind_isKeep (tkind)
3511                 || alkind_isOwned (tkind))
3512                || (!isfcnpass && alkind_isTemp (tkind)))
3513         {
3514           bool error = TRUE;
3515
3516           if (sRef_isLocalVar (fref))
3517             {
3518               sRef depRef = dependentReference (fref);
3519
3520               if (sRef_isValid (depRef) && sRef_isLocalVar (depRef))
3521                 {
3522                   error = FALSE;
3523                   sRef_kill (depRef, loc);
3524                   sRef_kill (fref, loc);
3525                 }
3526
3527             }
3528
3529           if (isfieldassign)
3530             {
3531               error = FALSE;
3532             }
3533
3534           if (canLoseLocalReference (fref, loc))
3535             {
3536               ;
3537             }
3538           else
3539             {
3540               if (error &&
3541                   (optgenerror 
3542                    (FLG_DEPENDENTTRANS,
3543                     message ("%s storage %q%q: %q",
3544                              alkind_capName (fkind),
3545                              sRef_unparseOpt (fref),
3546                              transferErrorMessage (transferType, tkind),
3547                              generateText (fexp, texp, tref, transferType)),
3548                     loc)))
3549                 {
3550                   DPRINTF (("Here: %s / %s", 
3551                             sRef_unparseFull (fref),
3552                             sRef_unparseFull (tref)));
3553
3554                   sRef_showAliasInfo (fref);
3555                 }
3556             }
3557         }
3558       else 
3559         {
3560           if (isassign && (alkind_isFresh (tkind) || alkind_isLocal (tkind)))
3561             {
3562               if (!tfix && !ffix)
3563                 {
3564                   sRef_setDependent (tref, loc);
3565                 }
3566             }
3567         }
3568     }
3569   else if (alkind_isShared (fkind))
3570     {
3571       setCodePoint ();
3572       /*
3573       ** xxx <- shared
3574       */
3575
3576       if (alkind_isOnly (tkind) 
3577           || (!isfcnpass 
3578               && (!(sRef_isObserver (tref) || sRef_isExposed (tref)) 
3579                   && alkind_isTemp (tkind))))
3580         {
3581           if (optgenerror
3582               (FLG_SHAREDTRANS,
3583                message ("%s storage %q%q: %q",
3584                         alkind_capName (fkind),
3585                         sRef_unparseOpt (fref),
3586                         transferErrorMessage (transferType, tkind),
3587                         generateText (fexp, texp, tref, transferType)),
3588                loc))
3589             {
3590               sRef_showAliasInfo (fref);
3591             }
3592         }
3593       else 
3594         {
3595           if (alkind_isFresh (tkind) || alkind_isLocal (tkind))
3596             {
3597               sRef_setShared (tref, loc);
3598             }
3599         }
3600     }
3601   else if (alkind_isKeep (fkind))
3602     {
3603       setCodePoint ();
3604
3605       if (alkind_isKeep (tkind) 
3606           || alkind_isLocal (tkind)
3607           || (isfcnreturn && sRef_isExposed (tref))
3608           || (iseitherassign 
3609               && (alkind_isOnly (tkind) || alkind_isOwned (tkind))))
3610         {
3611           sRef_setKept (fref, loc);
3612         }
3613       else if (isfcnpass 
3614                && (alkind_isTemp (tkind) || alkind_isOwned (tkind)))
3615         {
3616           ;
3617         }
3618       else 
3619         {
3620           if (!alkind_isError (tkind))
3621             {
3622               if (optgenerror
3623                   (FLG_KEEPTRANS,
3624                    message ("%s storage %q: %q",
3625                             alkind_capName (fkind),
3626                             transferErrorMessage (transferType, tkind),
3627                             generateText (fexp, texp, tref, transferType)),
3628                    loc))
3629                 {
3630                   sRef_showAliasInfo (fref);
3631                 }
3632             }
3633         }
3634     }
3635   else if (alkind_isTemp (fkind) || alkind_isKept (fkind))
3636     {
3637       /*
3638       ** xxx <- temp
3639       */
3640       
3641       if (alkind_isOnly (tkind)
3642           || alkind_isShared (tkind) 
3643           || (alkind_isTemp (fkind)
3644               && !isfcnreturn && alkind_isDependent (tkind))
3645           || alkind_isOwned (tkind)
3646           || alkind_isKeep (tkind))
3647         {
3648           if (!exprNode_isNullValue (fexp)
3649               && (ctype_isMutable (exprNode_getType (fexp))
3650                   || (ctype_isArray (exprNode_getType (fexp))
3651                       && sRef_isParam (fref)))
3652               && (!iseitherassign || sRef_isReference (tref)))
3653             {
3654               if (sRef_isThroughArrayFetch (fref))
3655                 {
3656                   if (optgenerror2
3657                       (alkind_isTemp (fkind) ? FLG_TEMPTRANS : FLG_KEPTTRANS,
3658                        FLG_STRICTUSERELEASED,
3659                        message ("%s storage %q%q: %q",
3660                                 alkind_capName (fkind),
3661                                 sRef_unparseOpt (fref),
3662                                 transferErrorMessage (transferType, tkind),
3663                                 generateText (fexp, texp, tref, transferType)),
3664                        loc))
3665                     {
3666                       sRef_showAliasInfo (fref);
3667                     }
3668                 }
3669               else
3670                 {
3671                   if (optgenerror
3672                       (alkind_isTemp (fkind) ? FLG_TEMPTRANS : FLG_KEPTTRANS,
3673                        message ("%s storage %q%q: %q",
3674                                 alkind_capName (fkind),
3675                                 sRef_unparseOpt (fref),
3676                                 transferErrorMessage (transferType, tkind),
3677                                 generateText (fexp, texp, tref, transferType)),
3678                        loc))
3679                     {
3680                       sRef_showAliasInfo (fref);
3681                     }
3682                 }
3683             }
3684         }
3685     }
3686   else if (alkind_isRefCounted (fkind) || alkind_isKillRef (fkind))
3687     {
3688       if (alkind_isNewRef (tkind))
3689         {
3690           /*
3691           ** check that the refs field has been modified
3692           */
3693
3694           if (!sRef_isConst (fref))
3695             {
3696               voptgenerror 
3697                 (FLG_REFCOUNTTRANS,
3698                  message ("Reference counted storage returned without modifying "
3699                           "reference count: %s",
3700                           exprNode_unparse (fexp)),
3701                  loc);
3702             }
3703         }
3704       else if (iseitherassign)
3705         {
3706           if (alkind_isRefCounted (fkind))
3707             {
3708               if (!sRef_isLocalVar (tref))
3709                 {
3710                   vgenhinterror 
3711                     (FLG_REFCOUNTTRANS,
3712                      message 
3713                      ("Assignment to non-local from reference counted storage: %s",
3714                       exprNode_unparse (fexp)),
3715                      cstring_makeLiteral 
3716                      ("Reference counted storage should call a function returning "
3717                       "a newref instead of direct assignments."),
3718                      loc);
3719                 }
3720               else
3721                 {
3722                   ;
3723                 }
3724             }
3725         }
3726       else /* fcnpass */
3727         {
3728           if (alkind_isRefCounted (tkind) || alkind_isTemp (tkind))
3729             {
3730               /* okay --- no change in state */
3731             }
3732           else if (alkind_isKillRef (tkind))
3733             {
3734               if (!ffix && !tfix && !(transferType == TT_FCNRETURN))
3735                 { 
3736                   sRef_killComplete (fref, loc); 
3737                 }
3738             }
3739           else 
3740             {
3741               if (!alkind_isError (tkind))
3742                 {
3743                   voptgenerror
3744                     (FLG_REFCOUNTTRANS,
3745                      message ("Reference counted storage %q: %q",
3746                               transferErrorMessage (transferType, tkind),
3747                               generateText (fexp, texp, tref, transferType)),
3748                      loc);
3749                 }
3750             }
3751         }
3752     }
3753   else
3754     {
3755       ;
3756     }
3757
3758   setCodePoint ();
3759   
3760   if (alkind_isOnly (tkind) || alkind_isKeep (tkind))
3761     {
3762       if (sRef_isAddress (fref))
3763         {
3764           voptgenerror
3765             (FLG_IMMEDIATETRANS,
3766              message ("Immediate address %q %q: %q", 
3767                       sRef_unparse (fref),
3768                       transferErrorMessage (transferType, tkind),
3769                       generateText (fexp, texp, tref, transferType)),
3770              loc);
3771           
3772           sRef_setAliasKind (fref, AK_ERROR, loc);
3773         }
3774       else 
3775         {
3776           if ((alkind_isUnknown (fkind) || alkind_isStatic (fkind))
3777               && !sRef_isDefinitelyNull (fref)
3778               && (!ffix && !tfix)
3779               && (!exprNode_isNullValue (fexp)))
3780             {
3781               flagcode errkind = alkind_isStatic (fkind) 
3782                 ? FLG_STATICTRANS : FLG_UNKNOWNTRANS;
3783
3784               if (transferType == TT_GLOBINIT)
3785                 {
3786                   if (errkind == FLG_STATICTRANS)
3787                     {
3788                       errkind = FLG_STATICINITTRANS;
3789                     }
3790                   else
3791                     {
3792                       errkind = FLG_UNKNOWNINITTRANS;
3793                     }
3794                 }
3795
3796               if (optgenerror 
3797                   (errkind,
3798                    message ("%s storage %s %q: %q",
3799                             alkind_capName (fkind),
3800                             exprNode_unparse (fexp),
3801                             transferErrorMessage (transferType, tkind),
3802                             generateText (fexp, texp, tref, transferType)),
3803                    loc))
3804                 {
3805                   sRef_showAliasInfo (fref);
3806                 }
3807             }
3808         }
3809       
3810       /* don't kill shared to suppress future messages */
3811       if (!alkind_isShared (fkind))
3812         {
3813           if (isassign)
3814             {
3815               if (!ffix) 
3816                 {
3817                   /*< yuk! should do this in aliasaux >*/
3818                    
3819                   if (!sRef_isNSLocalVar (tref) && !sRef_sameName (fref, tref))
3820                     {
3821                       if (!tfix)
3822                         {
3823                           sRef_setKeptComplete (fref, loc);
3824                         }
3825                       else
3826                         {
3827                           sRef_setKept (fref, loc);
3828                         }
3829                     }
3830                 }
3831             }
3832           else
3833             {
3834               if (!ffix) 
3835                 {
3836                   if (!tfix)
3837                     {
3838                       if (alkind_isKeep (tkind))
3839                         {
3840                           sRef_setKeptComplete (fref, loc);
3841                         }
3842                       else
3843                         {
3844                           sRef_killComplete (fref, loc); 
3845                         }
3846                     }
3847                   else
3848                     {
3849                       if (alkind_isKeep (tkind))
3850                         {
3851                           sRef_setKept (fref, loc);
3852                         }
3853                       else
3854                         {
3855                           sRef_kill (fref, loc);
3856                         }
3857                     }
3858                 }
3859             }
3860         }
3861     }
3862   else if (alkind_isOwned (tkind))
3863     {
3864       /* don't kill shared to suppress future messages */
3865       if (!alkind_isShared (fkind)) 
3866         {
3867           if (!isassign 
3868               || !sRef_sameName (fref, tref)) /* result of return parameter */
3869             {
3870               if (!ffix)
3871                 {
3872                   if (!tfix)
3873                     {
3874                       sRef_setDependentComplete (fref, loc);
3875                     }
3876                   else
3877                     {
3878                       sRef_setDependent (fref, loc);
3879                     }
3880                 }
3881             }
3882         }
3883     }
3884   else if (alkind_isShared (tkind))
3885     {
3886       if (alkind_isFresh (fkind) || alkind_isLocal (fkind))
3887         {
3888           if (!ffix) 
3889             {
3890               sRef_setShared (fref, loc);
3891             }
3892         }
3893     }
3894   else if (alkind_isUnknown (tkind) && context_getFlag (FLG_MEMIMPLICIT))
3895     {
3896       if (alkind_isDependent (fkind))
3897         {
3898           if (!exprNode_isNullValue (fexp)
3899               && ctype_isMutable (exprNode_getType (fexp))
3900               && (!iseitherassign || sRef_isReference (tref)))
3901             {
3902               if (transferChecks_canLoseReference (fref, loc))
3903                 {
3904                   ;
3905                 }
3906               else
3907                 {
3908                   if (optgenerror
3909                       (FLG_DEPENDENTTRANS,
3910                        message ("%s storage %q%q: %q",
3911                                 alkind_capName (fkind),
3912                                 sRef_unparseOpt (fref),
3913                                 transferErrorMessage (transferType, tkind),
3914                                 generateText (fexp, texp, tref, transferType)),
3915                        loc))
3916                     {
3917                       DPRINTF (("Here: %s / %s", sRef_unparseFull (fref),
3918                                 sRef_unparseFull (tref)));
3919                       sRef_showAliasInfo (fref);
3920                     }
3921                 }
3922             }
3923         }
3924     }
3925   else if (alkind_isNewRef (tkind))
3926     {
3927       if (!ffix && !tfix)
3928         { 
3929           sRef_killComplete (fref, loc);  
3930         }
3931     }
3932   else if (alkind_isKillRef (tkind))
3933     {
3934       if (transferType == TT_FCNRETURN)
3935         {
3936           if (sRef_isNewRef (fref))
3937             {
3938               if (optgenerror
3939                   (FLG_REFCOUNTTRANS,
3940                    message ("New reference returned as temp reference: %q",
3941                             generateText (fexp, texp, tref, transferType)),
3942                    loc))
3943                 {
3944                   sRef_showAliasInfo (fref);
3945                 }
3946               }
3947         }
3948       else
3949         {
3950           if (sRef_isNewRef (fref))
3951             {
3952               sRef_killComplete (fref, loc);
3953             }
3954           else 
3955             {
3956               if (sRef_isRefCounted (fref) 
3957                   && sRef_isCvar (fref)
3958                   && !sRef_isLocalVar (fref))
3959                 {
3960                   if (optgenerror
3961                       (FLG_REFCOUNTTRANS,
3962                        message 
3963                        ("External reference counted storage released: %q",
3964                         generateText (fexp, texp, tref, transferType)),
3965                        loc))
3966                     {
3967                       sRef_showAliasInfo (fref);
3968                     }
3969                 }
3970             }
3971         }
3972           
3973     }
3974   else
3975     {
3976       ;
3977     }
3978
3979   setCodePoint ();
3980 }
3981
3982 static void
3983 checkMetaStateConsistent (/*@exposed@*/ sRef fref, sRef tref, 
3984                           fileloc loc, /*@unused@*/ transferKind transferType)
3985 {
3986   /*
3987   ** Checks if it is consistent to leave storage marked as tref in state of fref.
3988   */
3989
3990   valueTable fvalues = sRef_getValueTable (fref);
3991   valueTable tvalues = sRef_getValueTable (tref);
3992   
3993   DPRINTF (("Metastate consistent: %s => %s",
3994             sRef_unparseFull (fref),
3995             sRef_unparseFull (tref)));
3996   
3997   if (valueTable_isUndefined (tvalues) || valueTable_isUndefined (fvalues)) {
3998     /* Cannot check without value tables.  An error was already detected. */
3999     DPRINTF (("No value table: %s / %s",
4000               bool_unparse (valueTable_isUndefined (tvalues)),
4001               bool_unparse (valueTable_isUndefined (fvalues))));
4002     return;
4003   }
4004
4005   valueTable_elements (fvalues, fkey, fval) {
4006     stateValue tval;
4007     metaStateInfo minfo;
4008
4009     DPRINTF (("Transfer: %s", fkey));
4010     tval = valueTable_lookup (tvalues, fkey);
4011     minfo = context_lookupMetaStateInfo (fkey);
4012
4013     if (!stateValue_isDefined (tval)) 
4014       {
4015         if (ctype_isUnknown (sRef_getType (fref)))
4016           {
4017             ; /* Okay, put in default values without knowing type */
4018           }
4019         else
4020           {
4021             /*@i#!@!!@*/
4022             DPRINTF (("Cannot find meta state for: %s / to: %s / %s", sRef_unparseFull (fref),
4023                       sRef_unparseFull (tref),
4024                       fkey));
4025           }
4026       }
4027     else
4028       {
4029         llassert (metaStateInfo_isDefined (minfo));
4030         
4031         if (stateValue_isError (fval) || stateValue_isError (tval))
4032           {
4033             ;
4034           }
4035         else if (sRef_isDefinitelyNull (fref)
4036                  || usymtab_isDefinitelyNull (fref))
4037           {
4038             ; /* No errors for null values in state transfers. */
4039           }
4040         
4041         else
4042           {
4043             stateCombinationTable sctable = metaStateInfo_getTransferTable (minfo);
4044             cstring msg = cstring_undefined;
4045             int nval = stateCombinationTable_lookup (sctable, 
4046                                                      stateValue_getValue (fval), 
4047                                                      stateValue_getValue (tval), 
4048                                                      &msg);
4049             
4050             if (nval == stateValue_error)
4051               {
4052                 if (transferType == TT_LEAVETRANS)
4053                   {
4054                     BADBRANCH;
4055                   }
4056                 else if (transferType == TT_GLOBRETURN)
4057                   {
4058                     if (optgenerror 
4059                         (FLG_STATETRANSFER,
4060                          message
4061                          ("Function returns with global %q in inconsistent state (%q is %q, should be %q)%q",
4062                           sRef_unparse (sRef_getRootBase (fref)),
4063                           sRef_unparse (fref),
4064                           stateValue_unparseValue (fval, minfo),
4065                           stateValue_unparseValue (tval, minfo),
4066                           cstring_isDefined (msg) 
4067                           ? message (": %s", msg) : cstring_undefined),
4068                          loc))
4069                       {
4070                         sRef_showMetaStateInfo (fref, fkey);
4071                       }             
4072                   }
4073                 else if (transferType == TT_GLOBPASS)
4074                   {
4075                     if (optgenerror 
4076                         (FLG_STATETRANSFER,
4077                          message
4078                          ("Function called with global %q in inconsistent state (%q is %q, should be %q)%q",
4079                           sRef_unparse (sRef_getRootBase (fref)),
4080                           stateValue_unparseValue (fval, minfo),
4081                           sRef_unparse (fref),
4082                           stateValue_unparseValue (tval, minfo),
4083                           cstring_isDefined (msg) 
4084                           ? message (": %s", msg) : cstring_undefined),
4085                          loc))
4086                       {
4087                         sRef_showMetaStateInfo (fref, fkey);
4088                       }             
4089                   }
4090                 else if (transferType == TT_PARAMRETURN)
4091                   {
4092                     if (optgenerror 
4093                         (FLG_STATETRANSFER,
4094                          message
4095                          ("Function returns with parameter %q in inconsistent state (%q is %q, should be %q)%q",
4096                           sRef_unparse (sRef_getRootBase (fref)),
4097                           sRef_unparse (fref),                  
4098                           stateValue_unparseValue (fval, minfo),
4099                           stateValue_unparseValue (tval, minfo),
4100                           cstring_isDefined (msg) 
4101                           ? message (": %s", msg) : cstring_undefined),
4102                          loc))
4103                       {
4104                         sRef_showMetaStateInfo (fref, fkey);
4105                       }
4106                   }
4107                 else
4108                   {
4109                     if (optgenerror 
4110                         (FLG_STATETRANSFER,
4111                          message
4112                          ("Invalid transfer from %q %x to %q (%q)%q",
4113                           stateValue_unparseValue (fval, minfo),
4114                           sRef_unparse (fref),
4115                           stateValue_unparseValue (tval, minfo),
4116                           sRef_unparse (tref),
4117                           cstring_isDefined (msg) 
4118                           ? message (": %s", msg) : cstring_undefined),
4119                          loc))
4120                       {
4121                         sRef_showMetaStateInfo (fref, fkey);
4122                       }
4123                   }
4124
4125               }
4126                     
4127             if (stateValue_getValue (fval) != nval)
4128               {
4129                 stateValue_updateValueLoc (fval, nval, loc);
4130               }
4131           }
4132       }
4133     
4134     DPRINTF (("Transfer: %s %s -> %s",
4135               fkey, stateValue_unparse (fval), stateValue_unparse (tval)));
4136   } end_valueTable_elements ;
4137 }
4138
4139 static void
4140 checkMetaStateTransfer (exprNode fexp, sRef fref, exprNode texp, sRef tref, 
4141                         exprNode fcn,
4142                         fileloc loc, transferKind /*@i32@*/ transferType)
4143 {
4144   valueTable fvalues = sRef_getValueTable (fref);
4145   valueTable tvalues = sRef_getValueTable (tref);
4146
4147   DPRINTF (("Metastate transfer: from %s", exprNode_unparse (fexp)));
4148   
4149   DPRINTF (("Metastate transfer: %s => %s",
4150             sRef_unparseFull (fref),
4151             sRef_unparseFull (tref)));
4152
4153   if (valueTable_isUndefined (tvalues) || valueTable_isUndefined (fvalues)) {
4154     /* Cannot check without value tables.  An error was already detected. */
4155     DPRINTF (("No value table: %s / %s",
4156               bool_unparse (valueTable_isUndefined (tvalues)),
4157               bool_unparse (valueTable_isUndefined (fvalues))));
4158     return;
4159   }
4160
4161   valueTable_elements (fvalues, fkey, fval) {
4162     stateValue tval;
4163     metaStateInfo minfo;
4164     stateCombinationTable sctable;
4165     cstring msg;
4166     int nval;
4167
4168     DPRINTF (("Transfer: %s", fkey));
4169     tval = valueTable_lookup (tvalues, fkey);
4170     minfo = context_lookupMetaStateInfo (fkey);
4171
4172     if (!stateValue_isDefined (tval)) 
4173       {
4174         if (ctype_isUnknown (sRef_getType (fref)))
4175           {
4176             ; /* Okay, put in default values without knowing type */
4177           }
4178         else
4179           {
4180             /*@i#!@!!@*/
4181             DPRINTF (("Metastate transfer: %s => %s",
4182                       exprNode_unparse (fexp), exprNode_unparse (texp)));
4183             DPRINTF (("Cannot find meta state for: %s / to: %s / %s", sRef_unparseFull (fref),
4184                       sRef_unparseFull (tref),
4185                       fkey));
4186           }
4187       }
4188     else
4189       {
4190         llassert (metaStateInfo_isDefined (minfo));
4191         
4192         if (stateValue_isError (fval))
4193           {
4194             ;
4195           }
4196         else if (stateValue_isError (tval))
4197           {
4198             if (sRef_isLocalVar (tref) && transferType == TT_DOASSIGN)
4199               {
4200                 /* Local assignments just replace state. */
4201                 stateValue_updateValueLoc (tval, stateValue_getValue (fval), loc);
4202                 DPRINTF (("Update: %s", stateValue_unparse (tval)));
4203               }
4204             else if (transferType == TT_FCNRETURN)
4205               {
4206                 ; /* Returning from an unannotated function */
4207               }
4208             else
4209               {
4210                 DPRINTF (("Transfer to error: %s / %s", sRef_unparseFull (tref),
4211                           transferType_unparse (transferType)));
4212               }
4213           }
4214         else 
4215           {
4216             DPRINTF (("Check: %s / %s / %s / %s", fkey,
4217                       metaStateInfo_unparse (minfo),
4218                       stateValue_unparse (fval),
4219                       stateValue_unparse (tval)));
4220             
4221             sctable = metaStateInfo_getTransferTable (minfo);
4222             msg = cstring_undefined;
4223             
4224             nval = stateCombinationTable_lookup (sctable, 
4225                                                  stateValue_getValue (fval), 
4226                                                  stateValue_getValue (tval), 
4227                                                  &msg);
4228             
4229             if (transferType == TT_DOASSIGN && sRef_isLocalVar (tref))
4230               {
4231                 /* Local assignments just replace state. */
4232                 DPRINTF (("No transfer error assigning to local: %s", msg));
4233                 stateValue_updateValueLoc (tval, stateValue_getValue (fval), loc);
4234                 DPRINTF (("Update: %s", stateValue_unparse (tval)));
4235               }
4236             else
4237               {
4238                 if (nval == stateValue_error)
4239                   {
4240                     /*@i32 print extra info for assignments@*/
4241                     
4242                     if (optgenerror 
4243                         (FLG_STATETRANSFER,
4244                          message
4245                          ("Invalid transfer from %q %x to %q%q: %q",
4246                           stateValue_unparseValue (fval, minfo),
4247                           sRef_unparse (fref),
4248                           stateValue_unparseValue (tval, minfo),
4249                           cstring_isDefined (msg) 
4250                           ? message (" (%s)", msg) : cstring_undefined,
4251                           transferErrorExcerpt (transferType, fexp, texp, fcn)),
4252                          loc))
4253                       {
4254                         sRef_showMetaStateInfo (fref, fkey);
4255                         sRef_showMetaStateInfo (tref, fkey);
4256                       }
4257                     else
4258                       {
4259                         DPRINTF (("Suppressed transfer error: %s", msg));
4260                       }
4261                   }
4262                 else
4263                   {
4264                     if (transferType == TT_FCNRETURN)
4265                       {
4266                         /*
4267                         ** Returning this reference from a function, mark this reference
4268                         ** so no lost reference errors are returned.
4269                         */ 
4270
4271                         stateValue_updateValueLoc (fval, stateValue_error, loc);
4272                       }
4273                     else if (stateValue_getValue (fval) != nval)
4274                       {
4275                         stateValue_updateValueLoc (fval, nval, loc);
4276                       }
4277                     else
4278                       {
4279                         ;
4280                       }
4281                   }
4282               }
4283           }
4284       }
4285     
4286     DPRINTF (("Transfer: %s %s -> %s",
4287               fkey, stateValue_unparse (fval), stateValue_unparse (tval)));
4288   } end_valueTable_elements ;
4289 }
4290
4291 /*
4292 ** assigns fexp := tref or passes fexp as a parameter, or returns fexp.
4293 **
4294 ** For assignments, sets alias and definition state accordingly.
4295 */
4296
4297 static void
4298 checkTransfer (exprNode fexp, /*@dependent@*/ sRef fref, 
4299                exprNode texp, /*@dependent@*/ sRef tref, 
4300                exprNode fcn,
4301                fileloc loc, transferKind transferType)
4302 {
4303   setCodePoint ();
4304
4305   if (context_inProtectVars ())
4306     {
4307       return;
4308     }
4309   
4310   DPRINTF (("Check transfer: %s => %s",
4311             sRef_unparse (fref),
4312             sRef_unparse (tref)));
4313   DPRINTF (("Check transfer: %s => %s",
4314             exprNode_unparse (fexp),
4315             exprNode_unparse (texp)));
4316
4317   checkMetaStateTransfer (fexp, fref, texp, tref, fcn,
4318                           loc, transferType);
4319
4320   /*
4321   ** for local references, we need to check
4322   ** the transfer for all possible aliases.
4323   */
4324
4325   if (sRef_isLocalVar (tref) && transferType != TT_DOASSIGN)
4326     {    
4327       sRefSet alias = usymtab_allAliases (tref);
4328
4329       sRefSet_realElements (alias, atref)
4330         {
4331           sRef abase = sRef_getRootBase (atref);
4332
4333           if (sRef_isKnown (atref)
4334               && !sRef_isLocalVar (abase) 
4335               && !sRef_isExternal (abase))
4336             {
4337               atref = sRef_updateSref (atref);
4338
4339               if (sRef_hasName (atref))
4340                 {
4341                   if (!sRef_isNew (atref) 
4342                       && !sRef_sameName (tref, atref))
4343                     {
4344                       context_setAliasAnnote (atref, tref);
4345                     }
4346                   
4347                   checkTransferAux (fexp, fref, TRUE, 
4348                                     texp, atref, FALSE,
4349                                     loc, transferType);
4350                   
4351                   context_clearAliasAnnote ();
4352                 }
4353             }
4354         } end_sRefSet_realElements;
4355
4356       sRefSet_free (alias);
4357     }
4358
4359   if (sRef_isLocalVar (fref))
4360     {    
4361       sRefSet alias = usymtab_allAliases (fref);
4362
4363       sRefSet_realElements (alias, afref)
4364         {
4365           sRef abase = sRef_getRootBase (afref);
4366
4367           if (sRef_isKnown (afref) 
4368               && !sRef_isLocalVar (abase)
4369               && !sRef_isExternal (abase))
4370             {
4371               afref = sRef_updateSref (afref);
4372
4373               if (sRef_hasName (afref))
4374                 {
4375                   if (!sRef_isNew (afref) 
4376                       && !sRef_sameName (afref, fref))
4377                     {
4378                       context_setAliasAnnote (afref, fref);
4379                     }
4380                   
4381                   checkTransferAux (fexp, afref, FALSE,
4382                                     texp, tref, TRUE,
4383                                     loc, transferType);
4384                   
4385                   context_clearAliasAnnote ();
4386                 }
4387             }
4388         } end_sRefSet_realElements;
4389
4390       sRefSet_free (alias);
4391     }
4392   
4393   setCodePoint ();
4394   checkTransferAux (fexp, fref, FALSE, texp, tref, FALSE, 
4395                     loc, transferType);
4396   setCodePoint ();  
4397 }
4398
4399 static /*@exposed@*/ sRef 
4400   dependentReference (sRef sr)
4401 {
4402   sRefSet ab = usymtab_aliasedBy (sr); /* yes, really mean aliasedBy */
4403
4404   DPRINTF (("Dependent reference: %s", sRef_unparse (sr)));
4405   DPRINTF (("Aliases: %s", sRefSet_unparse (ab)));
4406
4407   /*
4408   ** If there is a local variable that aliases sr, then there is no
4409   ** error.  Make the local an only.
4410   */
4411   
4412   if (!sRefSet_isEmpty (ab))
4413     {
4414       sRef res = sRef_undefined;
4415
4416       DPRINTF (("Here we are!"));
4417
4418       /*
4419       ** make one an only, others alias it
4420       */
4421                   
4422       sRefSet_realElements (ab, current)
4423         {
4424           if (sRef_isOwned (current))
4425             {
4426               res = current; 
4427               break;
4428             }
4429         } end_sRefSet_realElements;
4430
4431       if (sRef_isInvalid (res))
4432         {
4433           /* 
4434           ** evans - 2001-03-24
4435           ** No owned element, just choose one! 
4436           ** (Any reason for preference?)
4437           */
4438
4439           res = sRefSet_choose (ab);
4440         }
4441
4442       sRefSet_free (ab);
4443       return res;
4444     }
4445
4446   return sRef_undefined;
4447 }
4448
4449 bool transferChecks_canLoseReference (/*@dependent@*/ sRef sr, fileloc loc)
4450 {
4451   bool gotone = FALSE;
4452   sRefSet ab = usymtab_aliasedBy (sr); /* yes, really mean aliasedBy */
4453     
4454   /*
4455   ** if there is a local variable that aliases sr, then there is no
4456   ** error.  Make the local an only.
4457   */
4458   
4459   if (!sRefSet_isEmpty (ab))
4460     {
4461       /*
4462       ** make one an only, others alias it
4463       */
4464       
4465       sRefSet_realElements (ab, current)
4466         {
4467           sRef_setLastReference (current, sr, loc);
4468           gotone = TRUE;
4469           break;
4470         } end_sRefSet_realElements;
4471
4472       sRefSet_free (ab);
4473     }
4474
4475   return gotone;
4476 }
4477
4478 bool canLoseLocalReference (/*@dependent@*/ sRef sr, fileloc loc)
4479 {
4480   bool gotone = FALSE;
4481   sRefSet ab = usymtab_aliasedBy (sr); /* yes, really mean aliasedBy */
4482     
4483   /*
4484   ** if there is a local variable that aliases sr, then there is no
4485   ** error.  Make the local an only.
4486   */
4487   
4488   if (!sRefSet_isEmpty (ab))
4489     {
4490       /*
4491       ** make one an only, others alias it
4492       */
4493       
4494       sRefSet_realElements (ab, current)
4495         {
4496           if (sRef_isRealLocalVar (sRef_getRootBase (current)))
4497             {
4498               sRef_setLastReference (current, sr, loc);
4499               gotone = TRUE;
4500               break;
4501             }
4502         } end_sRefSet_realElements;
4503
4504       sRefSet_free (ab);
4505     }
4506
4507   return gotone;
4508 }
This page took 0.423755 seconds and 3 git commands to generate.