1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/clone.c
9  */
10 
11 #include "root/dsystem.h"
12 #include "root/root.h"
13 
14 #include "aggregate.h"
15 #include "scope.h"
16 #include "mtype.h"
17 #include "declaration.h"
18 #include "module.h"
19 #include "id.h"
20 #include "expression.h"
21 #include "statement.h"
22 #include "init.h"
23 #include "template.h"
24 #include "tokens.h"
25 
26 Expression *semantic(Expression *e, Scope *sc);
27 
28 /*******************************************
29  * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
30  */
mergeFuncAttrs(StorageClass s1,FuncDeclaration * f)31 StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f)
32 {
33     if (!f)
34         return s1;
35 
36     StorageClass s2 = (f->storage_class & STCdisable);
37     TypeFunction *tf = (TypeFunction *)f->type;
38     if (tf->trust == TRUSTsafe)
39         s2 |= STCsafe;
40     else if (tf->trust == TRUSTsystem)
41         s2 |= STCsystem;
42     else if (tf->trust == TRUSTtrusted)
43         s2 |= STCtrusted;
44     if (tf->purity != PUREimpure)
45         s2 |= STCpure;
46     if (tf->isnothrow)
47         s2 |= STCnothrow;
48     if (tf->isnogc)
49         s2 |= STCnogc;
50 
51     StorageClass stc = 0;
52     StorageClass sa = s1 & s2;
53     StorageClass so = s1 | s2;
54 
55     if (so & STCsystem)
56         stc |= STCsystem;
57     else if (sa & STCtrusted)
58         stc |= STCtrusted;
59     else if ((so & (STCtrusted | STCsafe)) == (STCtrusted | STCsafe))
60         stc |= STCtrusted;
61     else if (sa & STCsafe)
62         stc |= STCsafe;
63 
64     if (sa & STCpure)
65         stc |= STCpure;
66 
67     if (sa & STCnothrow)
68         stc |= STCnothrow;
69 
70     if (sa & STCnogc)
71         stc |= STCnogc;
72 
73     if (so & STCdisable)
74         stc |= STCdisable;
75 
76     return stc;
77 }
78 
79 /*******************************************
80  * Check given aggregate actually has an identity opAssign or not.
81  * Params:
82  *      ad = struct or class
83  *      sc = current scope
84  * Returns:
85  *      if found, returns FuncDeclaration of opAssign, otherwise null
86  */
hasIdentityOpAssign(AggregateDeclaration * ad,Scope * sc)87 FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc)
88 {
89     Dsymbol *assign = search_function(ad, Id::assign);
90     if (assign)
91     {
92         /* check identity opAssign exists
93          */
94         UnionExp er; new(&er) NullExp(ad->loc, ad->type);    // dummy rvalue
95         UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
96         el.exp()->type = ad->type;
97         Expressions a;
98         a.setDim(1);
99 
100         unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
101         sc = sc->push();
102         sc->tinst = NULL;
103         sc->minst = NULL;
104 
105         a[0] = er.exp();
106         FuncDeclaration *f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
107         if (!f)
108         {
109             a[0] = el.exp();
110             f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
111         }
112 
113         sc = sc->pop();
114         global.endGagging(errors);
115 
116         if (f)
117         {
118             if (f->errors)
119                 return NULL;
120             int varargs;
121             Parameters *fparams = f->getParameters(&varargs);
122             if (fparams->dim >= 1)
123             {
124                 Parameter *fparam0 = Parameter::getNth(fparams, 0);
125                 if (fparam0->type->toDsymbol(NULL) != ad)
126                     f = NULL;
127             }
128         }
129         // BUGS: This detection mechanism cannot find some opAssign-s like follows:
130         // struct S { void opAssign(ref immutable S) const; }
131         return f;
132     }
133     return NULL;
134 }
135 
136 /*******************************************
137  * We need an opAssign for the struct if
138  * it has a destructor or a postblit.
139  * We need to generate one if a user-specified one does not exist.
140  */
needOpAssign(StructDeclaration * sd)141 bool needOpAssign(StructDeclaration *sd)
142 {
143     //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
144     if (sd->isUnionDeclaration())
145         return false;
146 
147     if (sd->hasIdentityAssign)
148         goto Lneed;         // because has identity==elaborate opAssign
149 
150     if (sd->dtor || sd->postblit)
151         goto Lneed;
152 
153     /* If any of the fields need an opAssign, then we
154      * need it too.
155      */
156     for (size_t i = 0; i < sd->fields.dim; i++)
157     {
158         VarDeclaration *v = sd->fields[i];
159         if (v->storage_class & STCref)
160             continue;
161         if (v->overlapped)              // if field of a union
162             continue;                   // user must handle it themselves
163         Type *tv = v->type->baseElemOf();
164         if (tv->ty == Tstruct)
165         {
166             TypeStruct *ts = (TypeStruct *)tv;
167             if (ts->sym->isUnionDeclaration())
168                 continue;
169             if (needOpAssign(ts->sym))
170                 goto Lneed;
171         }
172     }
173     //printf("\tdontneed\n");
174     return false;
175 
176 Lneed:
177     //printf("\tneed\n");
178     return true;
179 }
180 
181 /******************************************
182  * Build opAssign for struct.
183  *      ref S opAssign(S s) { ... }
184  *
185  * Note that s will be constructed onto the stack, and probably
186  * copy-constructed in caller site.
187  *
188  * If S has copy copy construction and/or destructor,
189  * the body will make bit-wise object swap:
190  *          S __swap = this; // bit copy
191  *          this = s;        // bit copy
192  *          __swap.dtor();
193  * Instead of running the destructor on s, run it on tmp instead.
194  *
195  * Otherwise, the body will make member-wise assignments:
196  * Then, the body is:
197  *          this.field1 = s.field1;
198  *          this.field2 = s.field2;
199  *          ...;
200  */
buildOpAssign(StructDeclaration * sd,Scope * sc)201 FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
202 {
203     if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
204     {
205         sd->hasIdentityAssign = true;
206         return f;
207     }
208     // Even if non-identity opAssign is defined, built-in identity opAssign
209     // will be defined.
210 
211     if (!needOpAssign(sd))
212         return NULL;
213 
214     //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
215     StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
216     Loc declLoc = sd->loc;
217     Loc loc = Loc();    // internal code should have no loc to prevent coverage
218 
219     // One of our sub-field might have `@disable opAssign` so we need to
220     // check for it.
221     // In this event, it will be reflected by having `stc` (opAssign's
222     // storage class) include `STCdisabled`.
223     for (size_t i = 0; i < sd->fields.dim; i++)
224     {
225         VarDeclaration *v = sd->fields[i];
226         if (v->storage_class & STCref)
227             continue;
228         if (v->overlapped)
229             continue;
230         Type *tv = v->type->baseElemOf();
231         if (tv->ty != Tstruct)
232             continue;
233 
234         StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
235         stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
236     }
237 
238     if (sd->dtor || sd->postblit)
239     {
240         if (!sd->type->isAssignable())  // Bugzilla 13044
241             return NULL;
242         stc = mergeFuncAttrs(stc, sd->dtor);
243         if (stc & STCsafe)
244             stc = (stc & ~STCsafe) | STCtrusted;
245     }
246 
247     Parameters *fparams = new Parameters;
248     fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL));
249     TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref);
250 
251     FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
252     fop->storage_class |= STCinference;
253     fop->generated = true;
254     Expression *e = NULL;
255     if (stc & STCdisable)
256     {
257     }
258     else if (sd->dtor || sd->postblit)
259     {
260         /* Do swap this and rhs.
261          *    __swap = this; this = s; __swap.dtor();
262          */
263         //printf("\tswap copy\n");
264         Identifier *idtmp = Identifier::generateId("__swap");
265         VarDeclaration *tmp = NULL;
266         AssignExp *ec = NULL;
267         if (sd->dtor)
268         {
269             tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc));
270             tmp->storage_class |= STCnodtor | STCtemp | STCctfe;
271             e = new DeclarationExp(loc, tmp);
272             ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc));
273             e = Expression::combine(e, ec);
274         }
275         ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p));
276         e = Expression::combine(e, ec);
277         if (sd->dtor)
278         {
279             /* Instead of running the destructor on s, run it
280              * on tmp. This avoids needing to copy tmp back in to s.
281              */
282             Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, false);
283             ec2 = new CallExp(loc, ec2);
284             e = Expression::combine(e, ec2);
285         }
286     }
287     else
288     {
289         /* Do memberwise copy.
290          *
291          * If sd is a nested struct, its vthis field assignment is:
292          * 1. If it's nested in a class, it's a rebind of class reference.
293          * 2. If it's nested in a function or struct, it's an update of void*.
294          * In both cases, it will change the parent context.
295          */
296         //printf("\tmemberwise copy\n");
297         for (size_t i = 0; i < sd->fields.dim; i++)
298         {
299             VarDeclaration *v = sd->fields[i];
300             // this.v = s.v;
301             AssignExp *ec = new AssignExp(loc,
302                 new DotVarExp(loc, new ThisExp(loc), v),
303                 new DotVarExp(loc, new IdentifierExp(loc, Id::p), v));
304             e = Expression::combine(e, ec);
305         }
306     }
307     if (e)
308     {
309         Statement *s1 = new ExpStatement(loc, e);
310 
311         /* Add:
312          *   return this;
313          */
314         e = new ThisExp(loc);
315         Statement *s2 = new ReturnStatement(loc, e);
316 
317         fop->fbody = new CompoundStatement(loc, s1, s2);
318         tf->isreturn = true;
319     }
320 
321     sd->members->push(fop);
322     fop->addMember(sc, sd);
323     sd->hasIdentityAssign = true;        // temporary mark identity assignable
324 
325     unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
326     Scope *sc2 = sc->push();
327     sc2->stc = 0;
328     sc2->linkage = LINKd;
329 
330     fop->semantic(sc2);
331     fop->semantic2(sc2);
332     // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
333 
334     sc2->pop();
335     if (global.endGagging(errors))    // if errors happened
336     {
337         // Disable generated opAssign, because some members forbid identity assignment.
338         fop->storage_class |= STCdisable;
339         fop->fbody = NULL;  // remove fbody which contains the error
340     }
341 
342     //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
343 
344     return fop;
345 }
346 
347 /*******************************************
348  * We need an opEquals for the struct if
349  * any fields has an opEquals.
350  * Generate one if a user-specified one does not exist.
351  */
needOpEquals(StructDeclaration * sd)352 bool needOpEquals(StructDeclaration *sd)
353 {
354     //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
355     if (sd->isUnionDeclaration())
356         goto Ldontneed;
357 
358     if (sd->hasIdentityEquals)
359         goto Lneed;
360 
361     /* If any of the fields has an opEquals, then we
362      * need it too.
363      */
364     for (size_t i = 0; i < sd->fields.dim; i++)
365     {
366         VarDeclaration *v = sd->fields[i];
367         if (v->storage_class & STCref)
368             continue;
369         if (v->overlapped)
370             continue;
371         Type *tv = v->type->toBasetype();
372         Type *tvbase = tv->baseElemOf();
373         if (tvbase->ty == Tstruct)
374         {
375             TypeStruct *ts = (TypeStruct *)tvbase;
376             if (ts->sym->isUnionDeclaration())
377                 continue;
378             if (needOpEquals(ts->sym))
379                 goto Lneed;
380             if (ts->sym->aliasthis)     // Bugzilla 14806
381                 goto Lneed;
382         }
383         if (tv->isfloating())
384         {
385             // This is necessray for:
386             //  1. comparison of +0.0 and -0.0 should be true.
387             //  2. comparison of NANs should be false always.
388             goto Lneed;
389         }
390         if (tv->ty == Tarray)
391             goto Lneed;
392         if (tv->ty == Taarray)
393             goto Lneed;
394         if (tv->ty == Tclass)
395             goto Lneed;
396     }
397 Ldontneed:
398     //printf("\tdontneed\n");
399     return false;
400 
401 Lneed:
402     //printf("\tneed\n");
403     return true;
404 }
405 
406 /*******************************************
407  * Check given aggregate actually has an identity opEquals or not.
408  */
hasIdentityOpEquals(AggregateDeclaration * ad,Scope * sc)409 FuncDeclaration *hasIdentityOpEquals(AggregateDeclaration *ad,  Scope *sc)
410 {
411     Dsymbol *eq = search_function(ad, Id::eq);
412     if (eq)
413     {
414         /* check identity opEquals exists
415          */
416         UnionExp er; new(&er) NullExp(ad->loc, NULL);        // dummy rvalue
417         UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
418         Expressions a;
419         a.setDim(1);
420         for (size_t i = 0; i < 5; i++)
421         {
422             Type *tthis = NULL;         // dead-store to prevent spurious warning
423             switch (i)
424             {
425                 case 0:  tthis = ad->type;                  break;
426                 case 1:  tthis = ad->type->constOf();       break;
427                 case 2:  tthis = ad->type->immutableOf();   break;
428                 case 3:  tthis = ad->type->sharedOf();      break;
429                 case 4:  tthis = ad->type->sharedConstOf(); break;
430                 default: assert(0);
431             }
432             FuncDeclaration *f = NULL;
433 
434             unsigned errors = global.startGagging();    // Do not report errors, even if the template opAssign fbody makes it.
435             sc = sc->push();
436             sc->tinst = NULL;
437             sc->minst = NULL;
438 
439             for (size_t j = 0; j < 2; j++)
440             {
441                 a[0] = (j == 0 ? er.exp() : el.exp());
442                 a[0]->type = tthis;
443                 f = resolveFuncCall(ad->loc, sc, eq, NULL, tthis, &a, 1);
444                 if (f)
445                     break;
446             }
447 
448             sc = sc->pop();
449             global.endGagging(errors);
450 
451             if (f)
452             {
453                 if (f->errors)
454                     return NULL;
455                 return f;
456             }
457         }
458     }
459     return NULL;
460 }
461 
462 /******************************************
463  * Build opEquals for struct.
464  *      const bool opEquals(const S s) { ... }
465  *
466  * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated.
467  * Now, struct objects comparison s1 == s2 is translated to:
468  *      s1.tupleof == s2.tupleof
469  * to calculate structural equality. See EqualExp::op_overload.
470  */
buildOpEquals(StructDeclaration * sd,Scope * sc)471 FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc)
472 {
473     if (hasIdentityOpEquals(sd, sc))
474     {
475         sd->hasIdentityEquals = true;
476     }
477     return NULL;
478 }
479 
480 /******************************************
481  * Build __xopEquals for TypeInfo_Struct
482  *      static bool __xopEquals(ref const S p, ref const S q)
483  *      {
484  *          return p == q;
485  *      }
486  *
487  * This is called by TypeInfo.equals(p1, p2). If the struct does not support
488  * const objects comparison, it will throw "not implemented" Error in runtime.
489  */
buildXopEquals(StructDeclaration * sd,Scope * sc)490 FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
491 {
492     if (!needOpEquals(sd))
493         return NULL;        // bitwise comparison would work
494 
495     //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
496     if (Dsymbol *eq = search_function(sd, Id::eq))
497     {
498         if (FuncDeclaration *fd = eq->isFuncDeclaration())
499         {
500             TypeFunction *tfeqptr;
501             {
502                 Scope scx;
503 
504                 /* const bool opEquals(ref const S s);
505                  */
506                 Parameters *parameters = new Parameters;
507                 parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
508                 tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
509                 tfeqptr->mod = MODconst;
510                 tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
511             }
512             fd = fd->overloadExactMatch(tfeqptr);
513             if (fd)
514                 return fd;
515         }
516     }
517 
518     if (!sd->xerreq)
519     {
520         // object._xopEquals
521         Identifier *id = Identifier::idPool("_xopEquals");
522         Expression *e = new IdentifierExp(sd->loc, Id::empty);
523         e = new DotIdExp(sd->loc, e, Id::object);
524         e = new DotIdExp(sd->loc, e, id);
525         e = semantic(e, sc);
526         Dsymbol *s = getDsymbol(e);
527         assert(s);
528         sd->xerreq = s->isFuncDeclaration();
529     }
530 
531     Loc declLoc = Loc();    // loc is unnecessary so __xopEquals is never called directly
532     Loc loc = Loc();        // loc is unnecessary so errors are gagged
533 
534     Parameters *parameters = new Parameters;
535     parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
536     parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
537     TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
538 
539     Identifier *id = Id::xopEquals;
540     FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
541     fop->generated = true;
542     Expression *e1 = new IdentifierExp(loc, Id::p);
543     Expression *e2 = new IdentifierExp(loc, Id::q);
544     Expression *e = new EqualExp(TOKequal, loc, e1, e2);
545 
546     fop->fbody = new ReturnStatement(loc, e);
547 
548     unsigned errors = global.startGagging();    // Do not report errors
549     Scope *sc2 = sc->push();
550     sc2->stc = 0;
551     sc2->linkage = LINKd;
552 
553     fop->semantic(sc2);
554     fop->semantic2(sc2);
555 
556     sc2->pop();
557     if (global.endGagging(errors))    // if errors happened
558         fop = sd->xerreq;
559 
560     return fop;
561 }
562 
563 /******************************************
564  * Build __xopCmp for TypeInfo_Struct
565  *      static bool __xopCmp(ref const S p, ref const S q)
566  *      {
567  *          return p.opCmp(q);
568  *      }
569  *
570  * This is called by TypeInfo.compare(p1, p2). If the struct does not support
571  * const objects comparison, it will throw "not implemented" Error in runtime.
572  */
buildXopCmp(StructDeclaration * sd,Scope * sc)573 FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
574 {
575     //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
576     if (Dsymbol *cmp = search_function(sd, Id::cmp))
577     {
578         if (FuncDeclaration *fd = cmp->isFuncDeclaration())
579         {
580             TypeFunction *tfcmpptr;
581             {
582                 Scope scx;
583 
584                 /* const int opCmp(ref const S s);
585                  */
586                 Parameters *parameters = new Parameters;
587                 parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
588                 tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd);
589                 tfcmpptr->mod = MODconst;
590                 tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
591             }
592             fd = fd->overloadExactMatch(tfcmpptr);
593             if (fd)
594                 return fd;
595         }
596     }
597     else
598     {
599         // FIXME: doesn't work for recursive alias this
600         return NULL;
601     }
602 
603     if (!sd->xerrcmp)
604     {
605         // object._xopCmp
606         Identifier *id = Identifier::idPool("_xopCmp");
607         Expression *e = new IdentifierExp(sd->loc, Id::empty);
608         e = new DotIdExp(sd->loc, e, Id::object);
609         e = new DotIdExp(sd->loc, e, id);
610         e = semantic(e, sc);
611         Dsymbol *s = getDsymbol(e);
612         assert(s);
613         sd->xerrcmp = s->isFuncDeclaration();
614     }
615 
616     Loc declLoc = Loc();    // loc is unnecessary so __xopCmp is never called directly
617     Loc loc = Loc();        // loc is unnecessary so errors are gagged
618 
619     Parameters *parameters = new Parameters;
620     parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
621     parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
622     TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd);
623 
624     Identifier *id = Id::xopCmp;
625     FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
626     fop->generated = true;
627     Expression *e1 = new IdentifierExp(loc, Id::p);
628     Expression *e2 = new IdentifierExp(loc, Id::q);
629 #ifdef IN_GCC
630     Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2);
631 #else
632     Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1);
633 #endif
634 
635     fop->fbody = new ReturnStatement(loc, e);
636 
637     unsigned errors = global.startGagging();    // Do not report errors
638     Scope *sc2 = sc->push();
639     sc2->stc = 0;
640     sc2->linkage = LINKd;
641 
642     fop->semantic(sc2);
643     fop->semantic2(sc2);
644 
645     sc2->pop();
646     if (global.endGagging(errors))    // if errors happened
647         fop = sd->xerrcmp;
648 
649     return fop;
650 }
651 
652 /*******************************************
653  * We need a toHash for the struct if
654  * any fields has a toHash.
655  * Generate one if a user-specified one does not exist.
656  */
needToHash(StructDeclaration * sd)657 bool needToHash(StructDeclaration *sd)
658 {
659     //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
660     if (sd->isUnionDeclaration())
661         goto Ldontneed;
662 
663     if (sd->xhash)
664         goto Lneed;
665 
666     /* If any of the fields has an opEquals, then we
667      * need it too.
668      */
669     for (size_t i = 0; i < sd->fields.dim; i++)
670     {
671         VarDeclaration *v = sd->fields[i];
672         if (v->storage_class & STCref)
673             continue;
674         if (v->overlapped)
675             continue;
676         Type *tv = v->type->toBasetype();
677         Type *tvbase = tv->baseElemOf();
678         if (tvbase->ty == Tstruct)
679         {
680             TypeStruct *ts = (TypeStruct *)tvbase;
681             if (ts->sym->isUnionDeclaration())
682                 continue;
683             if (needToHash(ts->sym))
684                 goto Lneed;
685             if (ts->sym->aliasthis)     // Bugzilla 14948
686                 goto Lneed;
687         }
688         if (tv->isfloating())
689         {
690             // This is necessray for:
691             //  1. comparison of +0.0 and -0.0 should be true.
692             goto Lneed;
693         }
694         if (tv->ty == Tarray)
695             goto Lneed;
696         if (tv->ty == Taarray)
697             goto Lneed;
698         if (tv->ty == Tclass)
699             goto Lneed;
700     }
701 Ldontneed:
702     //printf("\tdontneed\n");
703     return false;
704 
705 Lneed:
706     //printf("\tneed\n");
707     return true;
708 }
709 
710 /******************************************
711  * Build __xtoHash for non-bitwise hashing
712  *      static hash_t xtoHash(ref const S p) nothrow @trusted;
713  */
buildXtoHash(StructDeclaration * sd,Scope * sc)714 FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
715 {
716     if (Dsymbol *s = search_function(sd, Id::tohash))
717     {
718         static TypeFunction *tftohash;
719         if (!tftohash)
720         {
721             tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
722             tftohash->mod = MODconst;
723             tftohash = (TypeFunction *)tftohash->merge();
724         }
725 
726         if (FuncDeclaration *fd = s->isFuncDeclaration())
727         {
728             fd = fd->overloadExactMatch(tftohash);
729             if (fd)
730                 return fd;
731         }
732     }
733 
734     if (!needToHash(sd))
735         return NULL;
736 
737     //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
738     Loc declLoc = Loc();    // loc is unnecessary so __xtoHash is never called directly
739     Loc loc = Loc();        // internal code should have no loc to prevent coverage
740 
741     Parameters *parameters = new Parameters();
742     parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
743     TypeFunction *tf = new TypeFunction(parameters, Type::thash_t, 0, LINKd, STCnothrow | STCtrusted);
744 
745     Identifier *id = Id::xtoHash;
746     FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
747     fop->generated = true;
748 
749     /* Do memberwise hashing.
750      *
751      * If sd is a nested struct, and if it's nested in a class, the calculated
752      * hash value will also contain the result of parent class's toHash().
753      */
754     const char *code =
755         "size_t h = 0;"
756         "foreach (i, T; typeof(p.tupleof))"
757         "    h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
758         "return h;";
759     fop->fbody = new CompileStatement(loc, new StringExp(loc, const_cast<char *>(code)));
760 
761     Scope *sc2 = sc->push();
762     sc2->stc = 0;
763     sc2->linkage = LINKd;
764 
765     fop->semantic(sc2);
766     fop->semantic2(sc2);
767 
768     sc2->pop();
769 
770     //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
771     return fop;
772 }
773 
774 /*****************************************
775  * Create inclusive postblit for struct by aggregating
776  * all the postblits in postblits[] with the postblits for
777  * all the members.
778  * Note the close similarity with AggregateDeclaration::buildDtor(),
779  * and the ordering changes (runs forward instead of backwards).
780  */
buildPostBlit(StructDeclaration * sd,Scope * sc)781 FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
782 {
783     //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
784     if (sd->isUnionDeclaration())
785         return NULL;
786 
787     StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
788     Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc;
789     Loc loc = Loc();    // internal code should have no loc to prevent coverage
790 
791     for (size_t i = 0; i < sd->postblits.dim; i++)
792     {
793         stc |= sd->postblits[i]->storage_class & STCdisable;
794     }
795 
796     Statements *a = new Statements();
797     for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++)
798     {
799         VarDeclaration *v = sd->fields[i];
800         if (v->storage_class & STCref)
801             continue;
802         if (v->overlapped)
803             continue;
804         Type *tv = v->type->baseElemOf();
805         if (tv->ty != Tstruct)
806             continue;
807         StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
808         if (!sdv->postblit)
809             continue;
810         assert(!sdv->isUnionDeclaration());
811         sdv->postblit->functionSemantic();
812 
813         stc = mergeFuncAttrs(stc, sdv->postblit);
814         stc = mergeFuncAttrs(stc, sdv->dtor);
815         if (stc & STCdisable)
816         {
817             a->setDim(0);
818             break;
819         }
820 
821         Expression *ex = NULL;
822         tv = v->type->toBasetype();
823         if (tv->ty == Tstruct)
824         {
825             // this.v.__xpostblit()
826 
827             ex = new ThisExp(loc);
828             ex = new DotVarExp(loc, ex, v);
829 
830             // This is a hack so we can call postblits on const/immutable objects.
831             ex = new AddrExp(loc, ex);
832             ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
833             ex = new PtrExp(loc, ex);
834             if (stc & STCsafe)
835                 stc = (stc & ~STCsafe) | STCtrusted;
836 
837             ex = new DotVarExp(loc, ex, sdv->postblit, false);
838             ex = new CallExp(loc, ex);
839         }
840         else
841         {
842             // __ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
843 
844             uinteger_t n = tv->numberOfElems(loc);
845             if (n == 0)
846                 continue;
847 
848             ex = new ThisExp(loc);
849             ex = new DotVarExp(loc, ex, v);
850 
851             // This is a hack so we can call postblits on const/immutable objects.
852             ex = new DotIdExp(loc, ex, Id::ptr);
853             ex = new CastExp(loc, ex, sdv->type->pointerTo());
854             if (stc & STCsafe)
855                 stc = (stc & ~STCsafe) | STCtrusted;
856 
857             ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
858                                        new IntegerExp(loc, n, Type::tsize_t));
859             // Prevent redundant bounds check
860             ((SliceExp *)ex)->upperIsInBounds = true;
861             ((SliceExp *)ex)->lowerIsLessThanUpper = true;
862 
863             ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayPostblit), ex);
864         }
865         a->push(new ExpStatement(loc, ex)); // combine in forward order
866 
867         /* Bugzilla 10972: When the following field postblit calls fail,
868          * this field should be destructed for Exception Safety.
869          */
870         if (!sdv->dtor)
871             continue;
872         sdv->dtor->functionSemantic();
873 
874         tv = v->type->toBasetype();
875         if (v->type->toBasetype()->ty == Tstruct)
876         {
877             // this.v.__xdtor()
878 
879             ex = new ThisExp(loc);
880             ex = new DotVarExp(loc, ex, v);
881 
882             // This is a hack so we can call destructors on const/immutable objects.
883             ex = new AddrExp(loc, ex);
884             ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
885             ex = new PtrExp(loc, ex);
886             if (stc & STCsafe)
887                 stc = (stc & ~STCsafe) | STCtrusted;
888 
889             ex = new DotVarExp(loc, ex, sdv->dtor, false);
890             ex = new CallExp(loc, ex);
891         }
892         else
893         {
894             // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
895 
896             uinteger_t n = tv->numberOfElems(loc);
897             //if (n == 0)
898             //    continue;
899 
900             ex = new ThisExp(loc);
901             ex = new DotVarExp(loc, ex, v);
902 
903             // This is a hack so we can call destructors on const/immutable objects.
904             ex = new DotIdExp(loc, ex, Id::ptr);
905             ex = new CastExp(loc, ex, sdv->type->pointerTo());
906             if (stc & STCsafe)
907                 stc = (stc & ~STCsafe) | STCtrusted;
908 
909             ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
910                                        new IntegerExp(loc, n, Type::tsize_t));
911             // Prevent redundant bounds check
912             ((SliceExp *)ex)->upperIsInBounds = true;
913             ((SliceExp *)ex)->lowerIsLessThanUpper = true;
914 
915             ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex);
916         }
917         a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
918     }
919 
920     // Build our own "postblit" which executes a, but only if needed.
921     if (a->dim || (stc & STCdisable))
922     {
923         //printf("Building __fieldPostBlit()\n");
924         PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
925         dd->generated = true;
926         dd->storage_class |= STCinference;
927         dd->fbody = (stc & STCdisable) ? NULL : new CompoundStatement(loc, a);
928         sd->postblits.shift(dd);
929         sd->members->push(dd);
930         dd->semantic(sc);
931     }
932 
933     FuncDeclaration *xpostblit = NULL;
934     switch (sd->postblits.dim)
935     {
936         case 0:
937             break;
938 
939         case 1:
940             xpostblit = sd->postblits[0];
941             break;
942 
943         default:
944             Expression *e = NULL;
945             stc = STCsafe | STCnothrow | STCpure | STCnogc;
946             for (size_t i = 0; i < sd->postblits.dim; i++)
947             {
948                 FuncDeclaration *fd = sd->postblits[i];
949                 stc = mergeFuncAttrs(stc, fd);
950                 if (stc & STCdisable)
951                 {
952                     e = NULL;
953                     break;
954                 }
955                 Expression *ex = new ThisExp(loc);
956                 ex = new DotVarExp(loc, ex, fd, false);
957                 ex = new CallExp(loc, ex);
958                 e = Expression::combine(e, ex);
959             }
960             PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
961             dd->storage_class |= STCinference;
962             dd->fbody = new ExpStatement(loc, e);
963             sd->members->push(dd);
964             dd->semantic(sc);
965             xpostblit = dd;
966             break;
967     }
968     // Add an __xpostblit alias to make the inclusive postblit accessible
969     if (xpostblit)
970     {
971         AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
972         alias->semantic(sc);
973         sd->members->push(alias);
974         alias->addMember(sc, sd); // add to symbol table
975     }
976     return xpostblit;
977 }
978 
979 /*****************************************
980  * Create inclusive destructor for struct/class by aggregating
981  * all the destructors in dtors[] with the destructors for
982  * all the members.
983  * Note the close similarity with StructDeclaration::buildPostBlit(),
984  * and the ordering changes (runs backward instead of forwards).
985  */
buildDtor(AggregateDeclaration * ad,Scope * sc)986 FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
987 {
988     //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
989     if (ad->isUnionDeclaration())
990         return NULL;
991 
992     StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
993     Loc declLoc = ad->dtors.dim ? ad->dtors[0]->loc : ad->loc;
994     Loc loc = Loc();    // internal code should have no loc to prevent coverage
995 
996     Expression *e = NULL;
997     for (size_t i = 0; i < ad->fields.dim; i++)
998     {
999         VarDeclaration *v = ad->fields[i];
1000         if (v->storage_class & STCref)
1001             continue;
1002         if (v->overlapped)
1003             continue;
1004         Type *tv = v->type->baseElemOf();
1005         if (tv->ty != Tstruct)
1006             continue;
1007         StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
1008         if (!sdv->dtor)
1009             continue;
1010         sdv->dtor->functionSemantic();
1011 
1012         stc = mergeFuncAttrs(stc, sdv->dtor);
1013         if (stc & STCdisable)
1014         {
1015             e = NULL;
1016             break;
1017         }
1018 
1019         Expression *ex = NULL;
1020         tv = v->type->toBasetype();
1021         if (tv->ty == Tstruct)
1022         {
1023             // this.v.__xdtor()
1024 
1025             ex = new ThisExp(loc);
1026             ex = new DotVarExp(loc, ex, v);
1027 
1028             // This is a hack so we can call destructors on const/immutable objects.
1029             ex = new AddrExp(loc, ex);
1030             ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
1031             ex = new PtrExp(loc, ex);
1032             if (stc & STCsafe)
1033                 stc = (stc & ~STCsafe) | STCtrusted;
1034 
1035             ex = new DotVarExp(loc, ex, sdv->dtor, false);
1036             ex = new CallExp(loc, ex);
1037         }
1038         else
1039         {
1040             // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
1041 
1042             uinteger_t n = tv->numberOfElems(loc);
1043             if (n == 0)
1044                 continue;
1045 
1046             ex = new ThisExp(loc);
1047             ex = new DotVarExp(loc, ex, v);
1048 
1049             // This is a hack so we can call destructors on const/immutable objects.
1050             ex = new DotIdExp(loc, ex, Id::ptr);
1051             ex = new CastExp(loc, ex, sdv->type->pointerTo());
1052             if (stc & STCsafe)
1053                 stc = (stc & ~STCsafe) | STCtrusted;
1054 
1055             ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
1056                                        new IntegerExp(loc, n, Type::tsize_t));
1057             // Prevent redundant bounds check
1058             ((SliceExp *)ex)->upperIsInBounds = true;
1059             ((SliceExp *)ex)->lowerIsLessThanUpper = true;
1060 
1061             ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex);
1062         }
1063         e = Expression::combine(ex, e); // combine in reverse order
1064     }
1065 
1066     /* Build our own "destructor" which executes e
1067      */
1068     if (e || (stc & STCdisable))
1069     {
1070         //printf("Building __fieldDtor()\n");
1071         DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
1072         dd->generated = true;
1073         dd->storage_class |= STCinference;
1074         dd->fbody = new ExpStatement(loc, e);
1075         ad->dtors.shift(dd);
1076         ad->members->push(dd);
1077         dd->semantic(sc);
1078     }
1079 
1080     FuncDeclaration *xdtor = NULL;
1081     switch (ad->dtors.dim)
1082     {
1083         case 0:
1084             break;
1085 
1086         case 1:
1087             xdtor = ad->dtors[0];
1088             break;
1089 
1090         default:
1091             e = NULL;
1092             stc = STCsafe | STCnothrow | STCpure | STCnogc;
1093             for (size_t i = 0; i < ad->dtors.dim; i++)
1094             {
1095                 FuncDeclaration *fd = ad->dtors[i];
1096                 stc = mergeFuncAttrs(stc, fd);
1097                 if (stc & STCdisable)
1098                 {
1099                     e = NULL;
1100                     break;
1101                 }
1102                 Expression *ex = new ThisExp(loc);
1103                 ex = new DotVarExp(loc, ex, fd, false);
1104                 ex = new CallExp(loc, ex);
1105                 e = Expression::combine(ex, e);
1106             }
1107             DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
1108             dd->generated = true;
1109             dd->storage_class |= STCinference;
1110             dd->fbody = new ExpStatement(loc, e);
1111             ad->members->push(dd);
1112             dd->semantic(sc);
1113             xdtor = dd;
1114             break;
1115     }
1116     // Add an __xdtor alias to make the inclusive dtor accessible
1117     if (xdtor)
1118     {
1119         AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
1120         alias->semantic(sc);
1121         ad->members->push(alias);
1122         alias->addMember(sc, ad); // add to symbol table
1123     }
1124     return xdtor;
1125 }
1126 
1127 /******************************************
1128  * Create inclusive invariant for struct/class by aggregating
1129  * all the invariants in invs[].
1130  *      void __invariant() const [pure nothrow @trusted]
1131  *      {
1132  *          invs[0](), invs[1](), ...;
1133  *      }
1134  */
buildInv(AggregateDeclaration * ad,Scope * sc)1135 FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc)
1136 {
1137     StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
1138     Loc declLoc = ad->loc;
1139     Loc loc = Loc();    // internal code should have no loc to prevent coverage
1140 
1141     switch (ad->invs.dim)
1142     {
1143         case 0:
1144             return NULL;
1145 
1146         case 1:
1147             // Don't return invs[0] so it has uniquely generated name.
1148             /* fall through */
1149 
1150         default:
1151             Expression *e = NULL;
1152             StorageClass stcx = 0;
1153             for (size_t i = 0; i < ad->invs.dim; i++)
1154             {
1155                 stc = mergeFuncAttrs(stc, ad->invs[i]);
1156                 if (stc & STCdisable)
1157                 {
1158                     // What should do?
1159                 }
1160                 StorageClass stcy = (ad->invs[i]->storage_class & STCsynchronized) |
1161                                     (ad->invs[i]->type->mod & MODshared ? STCshared : 0);
1162                 if (i == 0)
1163                     stcx = stcy;
1164                 else if (stcx ^ stcy)
1165                 {
1166             #if 1   // currently rejects
1167                     ad->error(ad->invs[i]->loc, "mixing invariants with shared/synchronized differene is not supported");
1168                     e = NULL;
1169                     break;
1170             #endif
1171                 }
1172                 e = Expression::combine(e, new CallExp(loc, new VarExp(loc, ad->invs[i], false)));
1173             }
1174             InvariantDeclaration *inv;
1175             inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
1176             inv->fbody = new ExpStatement(loc, e);
1177             ad->members->push(inv);
1178             inv->semantic(sc);
1179             return inv;
1180     }
1181 }
1182