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
26Expression *semantic(Expression *e, Scope *sc);
27
28/*******************************************
29 * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
30 */
31StorageClass 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 */
87FuncDeclaration *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 */
141bool 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
176Lneed:
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 */
201FuncDeclaration *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 */
352bool 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    }
397Ldontneed:
398    //printf("\tdontneed\n");
399    return false;
400
401Lneed:
402    //printf("\tneed\n");
403    return true;
404}
405
406/*******************************************
407 * Check given aggregate actually has an identity opEquals or not.
408 */
409FuncDeclaration *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 */
471FuncDeclaration *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 */
490FuncDeclaration *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 */
573FuncDeclaration *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 */
657bool 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    }
701Ldontneed:
702    //printf("\tdontneed\n");
703    return false;
704
705Lneed:
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 */
714FuncDeclaration *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 */
781FuncDeclaration *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 */
986FuncDeclaration *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 */
1135FuncDeclaration *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