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