]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/clone.c
9105d114eaa01b1449b121884b9fd0c19f4f2bc8
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 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
15 #include "root/root.h"
16 #include "aggregate.h"
19 #include "declaration.h"
22 #include "expression.h"
23 #include "statement.h"
28 Expression
*semantic(Expression
*e
, Scope
*sc
);
30 /*******************************************
31 * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
33 StorageClass
mergeFuncAttrs(StorageClass s1
, FuncDeclaration
*f
)
38 StorageClass s2
= (f
->storage_class
& STCdisable
);
39 TypeFunction
*tf
= (TypeFunction
*)f
->type
;
40 if (tf
->trust
== TRUSTsafe
)
42 else if (tf
->trust
== TRUSTsystem
)
44 else if (tf
->trust
== TRUSTtrusted
)
46 if (tf
->purity
!= PUREimpure
)
54 StorageClass sa
= s1
& s2
;
55 StorageClass so
= s1
| s2
;
59 else if (sa
& STCtrusted
)
61 else if ((so
& (STCtrusted
| STCsafe
)) == (STCtrusted
| STCsafe
))
63 else if (sa
& STCsafe
)
81 /*******************************************
82 * Check given aggregate actually has an identity opAssign or not.
84 * ad = struct or class
87 * if found, returns FuncDeclaration of opAssign, otherwise null
89 FuncDeclaration
*hasIdentityOpAssign(AggregateDeclaration
*ad
, Scope
*sc
)
91 Dsymbol
*assign
= search_function(ad
, Id::assign
);
94 /* check identity opAssign exists
96 UnionExp er
; new(&er
) NullExp(ad
->loc
, ad
->type
); // dummy rvalue
97 UnionExp el
; new(&el
) IdentifierExp(ad
->loc
, Id::p
); // dummy lvalue
98 el
.exp()->type
= ad
->type
;
102 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
108 FuncDeclaration
*f
= resolveFuncCall(ad
->loc
, sc
, assign
, NULL
, ad
->type
, &a
, 1);
112 f
= resolveFuncCall(ad
->loc
, sc
, assign
, NULL
, ad
->type
, &a
, 1);
116 global
.endGagging(errors
);
123 Parameters
*fparams
= f
->getParameters(&varargs
);
124 if (fparams
->dim
>= 1)
126 Parameter
*fparam0
= Parameter::getNth(fparams
, 0);
127 if (fparam0
->type
->toDsymbol(NULL
) != ad
)
131 // BUGS: This detection mechanism cannot find some opAssign-s like follows:
132 // struct S { void opAssign(ref immutable S) const; }
138 /*******************************************
139 * We need an opAssign for the struct if
140 * it has a destructor or a postblit.
141 * We need to generate one if a user-specified one does not exist.
143 bool needOpAssign(StructDeclaration
*sd
)
145 //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
146 if (sd
->isUnionDeclaration())
149 if (sd
->hasIdentityAssign
)
150 goto Lneed
; // because has identity==elaborate opAssign
152 if (sd
->dtor
|| sd
->postblit
)
155 /* If any of the fields need an opAssign, then we
158 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
160 VarDeclaration
*v
= sd
->fields
[i
];
161 if (v
->storage_class
& STCref
)
163 if (v
->overlapped
) // if field of a union
164 continue; // user must handle it themselves
165 Type
*tv
= v
->type
->baseElemOf();
166 if (tv
->ty
== Tstruct
)
168 TypeStruct
*ts
= (TypeStruct
*)tv
;
169 if (ts
->sym
->isUnionDeclaration())
171 if (needOpAssign(ts
->sym
))
175 //printf("\tdontneed\n");
179 //printf("\tneed\n");
183 /******************************************
184 * Build opAssign for struct.
185 * ref S opAssign(S s) { ... }
187 * Note that s will be constructed onto the stack, and probably
188 * copy-constructed in caller site.
190 * If S has copy copy construction and/or destructor,
191 * the body will make bit-wise object swap:
192 * S __swap = this; // bit copy
193 * this = s; // bit copy
195 * Instead of running the destructor on s, run it on tmp instead.
197 * Otherwise, the body will make member-wise assignments:
199 * this.field1 = s.field1;
200 * this.field2 = s.field2;
203 FuncDeclaration
*buildOpAssign(StructDeclaration
*sd
, Scope
*sc
)
205 if (FuncDeclaration
*f
= hasIdentityOpAssign(sd
, sc
))
207 sd
->hasIdentityAssign
= true;
210 // Even if non-identity opAssign is defined, built-in identity opAssign
213 if (!needOpAssign(sd
))
216 //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
217 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
218 Loc declLoc
= sd
->loc
;
219 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
221 // One of our sub-field might have `@disable opAssign` so we need to
223 // In this event, it will be reflected by having `stc` (opAssign's
224 // storage class) include `STCdisabled`.
225 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
227 VarDeclaration
*v
= sd
->fields
[i
];
228 if (v
->storage_class
& STCref
)
232 Type
*tv
= v
->type
->baseElemOf();
233 if (tv
->ty
!= Tstruct
)
236 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
237 stc
= mergeFuncAttrs(stc
, hasIdentityOpAssign(sdv
, sc
));
240 if (sd
->dtor
|| sd
->postblit
)
242 if (!sd
->type
->isAssignable()) // Bugzilla 13044
244 stc
= mergeFuncAttrs(stc
, sd
->dtor
);
246 stc
= (stc
& ~STCsafe
) | STCtrusted
;
249 Parameters
*fparams
= new Parameters
;
250 fparams
->push(new Parameter(STCnodtor
, sd
->type
, Id::p
, NULL
));
251 TypeFunction
*tf
= new TypeFunction(fparams
, sd
->handleType(), 0, LINKd
, stc
| STCref
);
253 FuncDeclaration
*fop
= new FuncDeclaration(declLoc
, Loc(), Id::assign
, stc
, tf
);
254 fop
->storage_class
|= STCinference
;
255 fop
->generated
= true;
256 Expression
*e
= NULL
;
257 if (stc
& STCdisable
)
260 else if (sd
->dtor
|| sd
->postblit
)
262 /* Do swap this and rhs.
263 * __swap = this; this = s; __swap.dtor();
265 //printf("\tswap copy\n");
266 Identifier
*idtmp
= Identifier::generateId("__swap");
267 VarDeclaration
*tmp
= NULL
;
268 AssignExp
*ec
= NULL
;
271 tmp
= new VarDeclaration(loc
, sd
->type
, idtmp
, new VoidInitializer(loc
));
272 tmp
->storage_class
|= STCnodtor
| STCtemp
| STCctfe
;
273 e
= new DeclarationExp(loc
, tmp
);
274 ec
= new BlitExp(loc
, new VarExp(loc
, tmp
), new ThisExp(loc
));
275 e
= Expression::combine(e
, ec
);
277 ec
= new BlitExp(loc
, new ThisExp(loc
), new IdentifierExp(loc
, Id::p
));
278 e
= Expression::combine(e
, ec
);
281 /* Instead of running the destructor on s, run it
282 * on tmp. This avoids needing to copy tmp back in to s.
284 Expression
*ec2
= new DotVarExp(loc
, new VarExp(loc
, tmp
), sd
->dtor
, false);
285 ec2
= new CallExp(loc
, ec2
);
286 e
= Expression::combine(e
, ec2
);
291 /* Do memberwise copy.
293 * If sd is a nested struct, its vthis field assignment is:
294 * 1. If it's nested in a class, it's a rebind of class reference.
295 * 2. If it's nested in a function or struct, it's an update of void*.
296 * In both cases, it will change the parent context.
298 //printf("\tmemberwise copy\n");
299 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
301 VarDeclaration
*v
= sd
->fields
[i
];
303 AssignExp
*ec
= new AssignExp(loc
,
304 new DotVarExp(loc
, new ThisExp(loc
), v
),
305 new DotVarExp(loc
, new IdentifierExp(loc
, Id::p
), v
));
306 e
= Expression::combine(e
, ec
);
311 Statement
*s1
= new ExpStatement(loc
, e
);
316 e
= new ThisExp(loc
);
317 Statement
*s2
= new ReturnStatement(loc
, e
);
319 fop
->fbody
= new CompoundStatement(loc
, s1
, s2
);
323 sd
->members
->push(fop
);
324 fop
->addMember(sc
, sd
);
325 sd
->hasIdentityAssign
= true; // temporary mark identity assignable
327 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
328 Scope
*sc2
= sc
->push();
330 sc2
->linkage
= LINKd
;
334 // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
337 if (global
.endGagging(errors
)) // if errors happened
339 // Disable generated opAssign, because some members forbid identity assignment.
340 fop
->storage_class
|= STCdisable
;
341 fop
->fbody
= NULL
; // remove fbody which contains the error
344 //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
349 /*******************************************
350 * We need an opEquals for the struct if
351 * any fields has an opEquals.
352 * Generate one if a user-specified one does not exist.
354 bool needOpEquals(StructDeclaration
*sd
)
356 //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
357 if (sd
->isUnionDeclaration())
360 if (sd
->hasIdentityEquals
)
363 /* If any of the fields has an opEquals, then we
366 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
368 VarDeclaration
*v
= sd
->fields
[i
];
369 if (v
->storage_class
& STCref
)
373 Type
*tv
= v
->type
->toBasetype();
374 Type
*tvbase
= tv
->baseElemOf();
375 if (tvbase
->ty
== Tstruct
)
377 TypeStruct
*ts
= (TypeStruct
*)tvbase
;
378 if (ts
->sym
->isUnionDeclaration())
380 if (needOpEquals(ts
->sym
))
382 if (ts
->sym
->aliasthis
) // Bugzilla 14806
385 if (tv
->isfloating())
387 // This is necessray for:
388 // 1. comparison of +0.0 and -0.0 should be true.
389 // 2. comparison of NANs should be false always.
392 if (tv
->ty
== Tarray
)
394 if (tv
->ty
== Taarray
)
396 if (tv
->ty
== Tclass
)
400 //printf("\tdontneed\n");
404 //printf("\tneed\n");
408 /*******************************************
409 * Check given aggregate actually has an identity opEquals or not.
411 FuncDeclaration
*hasIdentityOpEquals(AggregateDeclaration
*ad
, Scope
*sc
)
413 Dsymbol
*eq
= search_function(ad
, Id::eq
);
416 /* check identity opEquals exists
418 UnionExp er
; new(&er
) NullExp(ad
->loc
, NULL
); // dummy rvalue
419 UnionExp el
; new(&el
) IdentifierExp(ad
->loc
, Id::p
); // dummy lvalue
422 for (size_t i
= 0; i
< 5; i
++)
424 Type
*tthis
= NULL
; // dead-store to prevent spurious warning
427 case 0: tthis
= ad
->type
; break;
428 case 1: tthis
= ad
->type
->constOf(); break;
429 case 2: tthis
= ad
->type
->immutableOf(); break;
430 case 3: tthis
= ad
->type
->sharedOf(); break;
431 case 4: tthis
= ad
->type
->sharedConstOf(); break;
434 FuncDeclaration
*f
= NULL
;
436 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
441 for (size_t j
= 0; j
< 2; j
++)
443 a
[0] = (j
== 0 ? er
.exp() : el
.exp());
445 f
= resolveFuncCall(ad
->loc
, sc
, eq
, NULL
, tthis
, &a
, 1);
451 global
.endGagging(errors
);
464 /******************************************
465 * Build opEquals for struct.
466 * const bool opEquals(const S s) { ... }
468 * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated.
469 * Now, struct objects comparison s1 == s2 is translated to:
470 * s1.tupleof == s2.tupleof
471 * to calculate structural equality. See EqualExp::op_overload.
473 FuncDeclaration
*buildOpEquals(StructDeclaration
*sd
, Scope
*sc
)
475 if (hasIdentityOpEquals(sd
, sc
))
477 sd
->hasIdentityEquals
= true;
482 /******************************************
483 * Build __xopEquals for TypeInfo_Struct
484 * static bool __xopEquals(ref const S p, ref const S q)
489 * This is called by TypeInfo.equals(p1, p2). If the struct does not support
490 * const objects comparison, it will throw "not implemented" Error in runtime.
492 FuncDeclaration
*buildXopEquals(StructDeclaration
*sd
, Scope
*sc
)
494 if (!needOpEquals(sd
))
495 return NULL
; // bitwise comparison would work
497 //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
498 if (Dsymbol
*eq
= search_function(sd
, Id::eq
))
500 if (FuncDeclaration
*fd
= eq
->isFuncDeclaration())
502 TypeFunction
*tfeqptr
;
506 /* const bool opEquals(ref const S s);
508 Parameters
*parameters
= new Parameters
;
509 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, NULL
, NULL
));
510 tfeqptr
= new TypeFunction(parameters
, Type::tbool
, 0, LINKd
);
511 tfeqptr
->mod
= MODconst
;
512 tfeqptr
= (TypeFunction
*)tfeqptr
->semantic(Loc(), &scx
);
514 fd
= fd
->overloadExactMatch(tfeqptr
);
523 Identifier
*id
= Identifier::idPool("_xopEquals");
524 Expression
*e
= new IdentifierExp(sd
->loc
, Id::empty
);
525 e
= new DotIdExp(sd
->loc
, e
, Id::object
);
526 e
= new DotIdExp(sd
->loc
, e
, id
);
528 Dsymbol
*s
= getDsymbol(e
);
530 sd
->xerreq
= s
->isFuncDeclaration();
533 Loc declLoc
= Loc(); // loc is unnecessary so __xopEquals is never called directly
534 Loc loc
= Loc(); // loc is unnecessary so errors are gagged
536 Parameters
*parameters
= new Parameters
;
537 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, Id::p
, NULL
));
538 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, Id::q
, NULL
));
539 TypeFunction
*tf
= new TypeFunction(parameters
, Type::tbool
, 0, LINKd
);
541 Identifier
*id
= Id::xopEquals
;
542 FuncDeclaration
*fop
= new FuncDeclaration(declLoc
, Loc(), id
, STCstatic
, tf
);
543 fop
->generated
= true;
544 Expression
*e1
= new IdentifierExp(loc
, Id::p
);
545 Expression
*e2
= new IdentifierExp(loc
, Id::q
);
546 Expression
*e
= new EqualExp(TOKequal
, loc
, e1
, e2
);
548 fop
->fbody
= new ReturnStatement(loc
, e
);
550 unsigned errors
= global
.startGagging(); // Do not report errors
551 Scope
*sc2
= sc
->push();
553 sc2
->linkage
= LINKd
;
559 if (global
.endGagging(errors
)) // if errors happened
565 /******************************************
566 * Build __xopCmp for TypeInfo_Struct
567 * static bool __xopCmp(ref const S p, ref const S q)
572 * This is called by TypeInfo.compare(p1, p2). If the struct does not support
573 * const objects comparison, it will throw "not implemented" Error in runtime.
575 FuncDeclaration
*buildXopCmp(StructDeclaration
*sd
, Scope
*sc
)
577 //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
578 if (Dsymbol
*cmp
= search_function(sd
, Id::cmp
))
580 if (FuncDeclaration
*fd
= cmp
->isFuncDeclaration())
582 TypeFunction
*tfcmpptr
;
586 /* const int opCmp(ref const S s);
588 Parameters
*parameters
= new Parameters
;
589 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, NULL
, NULL
));
590 tfcmpptr
= new TypeFunction(parameters
, Type::tint32
, 0, LINKd
);
591 tfcmpptr
->mod
= MODconst
;
592 tfcmpptr
= (TypeFunction
*)tfcmpptr
->semantic(Loc(), &scx
);
594 fd
= fd
->overloadExactMatch(tfcmpptr
);
601 // FIXME: doesn't work for recursive alias this
608 Identifier
*id
= Identifier::idPool("_xopCmp");
609 Expression
*e
= new IdentifierExp(sd
->loc
, Id::empty
);
610 e
= new DotIdExp(sd
->loc
, e
, Id::object
);
611 e
= new DotIdExp(sd
->loc
, e
, id
);
613 Dsymbol
*s
= getDsymbol(e
);
615 sd
->xerrcmp
= s
->isFuncDeclaration();
618 Loc declLoc
= Loc(); // loc is unnecessary so __xopCmp is never called directly
619 Loc loc
= Loc(); // loc is unnecessary so errors are gagged
621 Parameters
*parameters
= new Parameters
;
622 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, Id::p
, NULL
));
623 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, Id::q
, NULL
));
624 TypeFunction
*tf
= new TypeFunction(parameters
, Type::tint32
, 0, LINKd
);
626 Identifier
*id
= Id::xopCmp
;
627 FuncDeclaration
*fop
= new FuncDeclaration(declLoc
, Loc(), id
, STCstatic
, tf
);
628 fop
->generated
= true;
629 Expression
*e1
= new IdentifierExp(loc
, Id::p
);
630 Expression
*e2
= new IdentifierExp(loc
, Id::q
);
632 Expression
*e
= new CallExp(loc
, new DotIdExp(loc
, e1
, Id::cmp
), e2
);
634 Expression
*e
= new CallExp(loc
, new DotIdExp(loc
, e2
, Id::cmp
), e1
);
637 fop
->fbody
= new ReturnStatement(loc
, e
);
639 unsigned errors
= global
.startGagging(); // Do not report errors
640 Scope
*sc2
= sc
->push();
642 sc2
->linkage
= LINKd
;
648 if (global
.endGagging(errors
)) // if errors happened
654 /*******************************************
655 * We need a toHash for the struct if
656 * any fields has a toHash.
657 * Generate one if a user-specified one does not exist.
659 bool needToHash(StructDeclaration
*sd
)
661 //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
662 if (sd
->isUnionDeclaration())
668 /* If any of the fields has an opEquals, then we
671 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
673 VarDeclaration
*v
= sd
->fields
[i
];
674 if (v
->storage_class
& STCref
)
678 Type
*tv
= v
->type
->toBasetype();
679 Type
*tvbase
= tv
->baseElemOf();
680 if (tvbase
->ty
== Tstruct
)
682 TypeStruct
*ts
= (TypeStruct
*)tvbase
;
683 if (ts
->sym
->isUnionDeclaration())
685 if (needToHash(ts
->sym
))
687 if (ts
->sym
->aliasthis
) // Bugzilla 14948
690 if (tv
->isfloating())
692 // This is necessray for:
693 // 1. comparison of +0.0 and -0.0 should be true.
696 if (tv
->ty
== Tarray
)
698 if (tv
->ty
== Taarray
)
700 if (tv
->ty
== Tclass
)
704 //printf("\tdontneed\n");
708 //printf("\tneed\n");
712 /******************************************
713 * Build __xtoHash for non-bitwise hashing
714 * static hash_t xtoHash(ref const S p) nothrow @trusted;
716 FuncDeclaration
*buildXtoHash(StructDeclaration
*sd
, Scope
*sc
)
718 if (Dsymbol
*s
= search_function(sd
, Id::tohash
))
720 static TypeFunction
*tftohash
;
723 tftohash
= new TypeFunction(NULL
, Type::thash_t
, 0, LINKd
);
724 tftohash
->mod
= MODconst
;
725 tftohash
= (TypeFunction
*)tftohash
->merge();
728 if (FuncDeclaration
*fd
= s
->isFuncDeclaration())
730 fd
= fd
->overloadExactMatch(tftohash
);
739 //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
740 Loc declLoc
= Loc(); // loc is unnecessary so __xtoHash is never called directly
741 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
743 Parameters
*parameters
= new Parameters();
744 parameters
->push(new Parameter(STCref
| STCconst
, sd
->type
, Id::p
, NULL
));
745 TypeFunction
*tf
= new TypeFunction(parameters
, Type::thash_t
, 0, LINKd
, STCnothrow
| STCtrusted
);
747 Identifier
*id
= Id::xtoHash
;
748 FuncDeclaration
*fop
= new FuncDeclaration(declLoc
, Loc(), id
, STCstatic
, tf
);
749 fop
->generated
= true;
751 /* Do memberwise hashing.
753 * If sd is a nested struct, and if it's nested in a class, the calculated
754 * hash value will also contain the result of parent class's toHash().
758 "foreach (i, T; typeof(p.tupleof))"
759 " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
761 fop
->fbody
= new CompileStatement(loc
, new StringExp(loc
, const_cast<char *>(code
)));
763 Scope
*sc2
= sc
->push();
765 sc2
->linkage
= LINKd
;
772 //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
776 /*****************************************
777 * Create inclusive postblit for struct by aggregating
778 * all the postblits in postblits[] with the postblits for
780 * Note the close similarity with AggregateDeclaration::buildDtor(),
781 * and the ordering changes (runs forward instead of backwards).
783 FuncDeclaration
*buildPostBlit(StructDeclaration
*sd
, Scope
*sc
)
785 //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
786 if (sd
->isUnionDeclaration())
789 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
790 Loc declLoc
= sd
->postblits
.dim
? sd
->postblits
[0]->loc
: sd
->loc
;
791 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
793 for (size_t i
= 0; i
< sd
->postblits
.dim
; i
++)
795 stc
|= sd
->postblits
[i
]->storage_class
& STCdisable
;
798 Statements
*a
= new Statements();
799 for (size_t i
= 0; i
< sd
->fields
.dim
&& !(stc
& STCdisable
); i
++)
801 VarDeclaration
*v
= sd
->fields
[i
];
802 if (v
->storage_class
& STCref
)
806 Type
*tv
= v
->type
->baseElemOf();
807 if (tv
->ty
!= Tstruct
)
809 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
812 assert(!sdv
->isUnionDeclaration());
813 sdv
->postblit
->functionSemantic();
815 stc
= mergeFuncAttrs(stc
, sdv
->postblit
);
816 stc
= mergeFuncAttrs(stc
, sdv
->dtor
);
817 if (stc
& STCdisable
)
823 Expression
*ex
= NULL
;
824 tv
= v
->type
->toBasetype();
825 if (tv
->ty
== Tstruct
)
827 // this.v.__xpostblit()
829 ex
= new ThisExp(loc
);
830 ex
= new DotVarExp(loc
, ex
, v
);
832 // This is a hack so we can call postblits on const/immutable objects.
833 ex
= new AddrExp(loc
, ex
);
834 ex
= new CastExp(loc
, ex
, v
->type
->mutableOf()->pointerTo());
835 ex
= new PtrExp(loc
, ex
);
837 stc
= (stc
& ~STCsafe
) | STCtrusted
;
839 ex
= new DotVarExp(loc
, ex
, sdv
->postblit
, false);
840 ex
= new CallExp(loc
, ex
);
844 // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
847 while (tv
->ty
== Tsarray
)
849 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
850 tv
= tv
->nextOf()->toBasetype();
855 ex
= new ThisExp(loc
);
856 ex
= new DotVarExp(loc
, ex
, v
);
858 // This is a hack so we can call postblits on const/immutable objects.
859 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
860 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
862 stc
= (stc
& ~STCsafe
) | STCtrusted
;
864 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
865 new IntegerExp(loc
, n
, Type::tsize_t
));
866 // Prevent redundant bounds check
867 ((SliceExp
*)ex
)->upperIsInBounds
= true;
868 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
870 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayPostblit
), ex
);
872 a
->push(new ExpStatement(loc
, ex
)); // combine in forward order
874 /* Bugzilla 10972: When the following field postblit calls fail,
875 * this field should be destructed for Exception Safety.
879 sdv
->dtor
->functionSemantic();
881 tv
= v
->type
->toBasetype();
882 if (v
->type
->toBasetype()->ty
== Tstruct
)
886 ex
= new ThisExp(loc
);
887 ex
= new DotVarExp(loc
, ex
, v
);
889 // This is a hack so we can call destructors on const/immutable objects.
890 ex
= new AddrExp(loc
, ex
);
891 ex
= new CastExp(loc
, ex
, v
->type
->mutableOf()->pointerTo());
892 ex
= new PtrExp(loc
, ex
);
894 stc
= (stc
& ~STCsafe
) | STCtrusted
;
896 ex
= new DotVarExp(loc
, ex
, sdv
->dtor
, false);
897 ex
= new CallExp(loc
, ex
);
901 // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
904 while (tv
->ty
== Tsarray
)
906 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
907 tv
= tv
->nextOf()->toBasetype();
912 ex
= new ThisExp(loc
);
913 ex
= new DotVarExp(loc
, ex
, v
);
915 // This is a hack so we can call destructors on const/immutable objects.
916 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
917 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
919 stc
= (stc
& ~STCsafe
) | STCtrusted
;
921 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
922 new IntegerExp(loc
, n
, Type::tsize_t
));
923 // Prevent redundant bounds check
924 ((SliceExp
*)ex
)->upperIsInBounds
= true;
925 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
927 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayDtor
), ex
);
929 a
->push(new OnScopeStatement(loc
, TOKon_scope_failure
, new ExpStatement(loc
, ex
)));
932 // Build our own "postblit" which executes a, but only if needed.
933 if (a
->dim
|| (stc
& STCdisable
))
935 //printf("Building __fieldPostBlit()\n");
936 PostBlitDeclaration
*dd
= new PostBlitDeclaration(declLoc
, Loc(), stc
, Id::__fieldPostblit
);
937 dd
->generated
= true;
938 dd
->storage_class
|= STCinference
;
939 dd
->fbody
= (stc
& STCdisable
) ? NULL
: new CompoundStatement(loc
, a
);
940 sd
->postblits
.shift(dd
);
941 sd
->members
->push(dd
);
945 FuncDeclaration
*xpostblit
= NULL
;
946 switch (sd
->postblits
.dim
)
952 xpostblit
= sd
->postblits
[0];
956 Expression
*e
= NULL
;
957 stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
958 for (size_t i
= 0; i
< sd
->postblits
.dim
; i
++)
960 FuncDeclaration
*fd
= sd
->postblits
[i
];
961 stc
= mergeFuncAttrs(stc
, fd
);
962 if (stc
& STCdisable
)
967 Expression
*ex
= new ThisExp(loc
);
968 ex
= new DotVarExp(loc
, ex
, fd
, false);
969 ex
= new CallExp(loc
, ex
);
970 e
= Expression::combine(e
, ex
);
972 PostBlitDeclaration
*dd
= new PostBlitDeclaration(declLoc
, Loc(), stc
, Id::__aggrPostblit
);
973 dd
->storage_class
|= STCinference
;
974 dd
->fbody
= new ExpStatement(loc
, e
);
975 sd
->members
->push(dd
);
980 // Add an __xpostblit alias to make the inclusive postblit accessible
983 AliasDeclaration
*alias
= new AliasDeclaration(Loc(), Id::__xpostblit
, xpostblit
);
985 sd
->members
->push(alias
);
986 alias
->addMember(sc
, sd
); // add to symbol table
991 /*****************************************
992 * Create inclusive destructor for struct/class by aggregating
993 * all the destructors in dtors[] with the destructors for
995 * Note the close similarity with StructDeclaration::buildPostBlit(),
996 * and the ordering changes (runs backward instead of forwards).
998 FuncDeclaration
*buildDtor(AggregateDeclaration
*ad
, Scope
*sc
)
1000 //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
1001 if (ad
->isUnionDeclaration())
1004 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1005 Loc declLoc
= ad
->dtors
.dim
? ad
->dtors
[0]->loc
: ad
->loc
;
1006 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
1008 Expression
*e
= NULL
;
1009 for (size_t i
= 0; i
< ad
->fields
.dim
; i
++)
1011 VarDeclaration
*v
= ad
->fields
[i
];
1012 if (v
->storage_class
& STCref
)
1016 Type
*tv
= v
->type
->baseElemOf();
1017 if (tv
->ty
!= Tstruct
)
1019 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
1022 sdv
->dtor
->functionSemantic();
1024 stc
= mergeFuncAttrs(stc
, sdv
->dtor
);
1025 if (stc
& STCdisable
)
1031 Expression
*ex
= NULL
;
1032 tv
= v
->type
->toBasetype();
1033 if (tv
->ty
== Tstruct
)
1037 ex
= new ThisExp(loc
);
1038 ex
= new DotVarExp(loc
, ex
, v
);
1040 // This is a hack so we can call destructors on const/immutable objects.
1041 ex
= new AddrExp(loc
, ex
);
1042 ex
= new CastExp(loc
, ex
, v
->type
->mutableOf()->pointerTo());
1043 ex
= new PtrExp(loc
, ex
);
1045 stc
= (stc
& ~STCsafe
) | STCtrusted
;
1047 ex
= new DotVarExp(loc
, ex
, sdv
->dtor
, false);
1048 ex
= new CallExp(loc
, ex
);
1052 // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
1055 while (tv
->ty
== Tsarray
)
1057 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
1058 tv
= tv
->nextOf()->toBasetype();
1063 ex
= new ThisExp(loc
);
1064 ex
= new DotVarExp(loc
, ex
, v
);
1066 // This is a hack so we can call destructors on const/immutable objects.
1067 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
1068 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
1070 stc
= (stc
& ~STCsafe
) | STCtrusted
;
1072 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
1073 new IntegerExp(loc
, n
, Type::tsize_t
));
1074 // Prevent redundant bounds check
1075 ((SliceExp
*)ex
)->upperIsInBounds
= true;
1076 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
1078 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayDtor
), ex
);
1080 e
= Expression::combine(ex
, e
); // combine in reverse order
1083 /* Build our own "destructor" which executes e
1085 if (e
|| (stc
& STCdisable
))
1087 //printf("Building __fieldDtor()\n");
1088 DtorDeclaration
*dd
= new DtorDeclaration(declLoc
, Loc(), stc
, Id::__fieldDtor
);
1089 dd
->generated
= true;
1090 dd
->storage_class
|= STCinference
;
1091 dd
->fbody
= new ExpStatement(loc
, e
);
1092 ad
->dtors
.shift(dd
);
1093 ad
->members
->push(dd
);
1097 FuncDeclaration
*xdtor
= NULL
;
1098 switch (ad
->dtors
.dim
)
1104 xdtor
= ad
->dtors
[0];
1109 stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1110 for (size_t i
= 0; i
< ad
->dtors
.dim
; i
++)
1112 FuncDeclaration
*fd
= ad
->dtors
[i
];
1113 stc
= mergeFuncAttrs(stc
, fd
);
1114 if (stc
& STCdisable
)
1119 Expression
*ex
= new ThisExp(loc
);
1120 ex
= new DotVarExp(loc
, ex
, fd
, false);
1121 ex
= new CallExp(loc
, ex
);
1122 e
= Expression::combine(ex
, e
);
1124 DtorDeclaration
*dd
= new DtorDeclaration(declLoc
, Loc(), stc
, Id::__aggrDtor
);
1125 dd
->generated
= true;
1126 dd
->storage_class
|= STCinference
;
1127 dd
->fbody
= new ExpStatement(loc
, e
);
1128 ad
->members
->push(dd
);
1133 // Add an __xdtor alias to make the inclusive dtor accessible
1136 AliasDeclaration
*alias
= new AliasDeclaration(Loc(), Id::__xdtor
, xdtor
);
1137 alias
->semantic(sc
);
1138 ad
->members
->push(alias
);
1139 alias
->addMember(sc
, ad
); // add to symbol table
1144 /******************************************
1145 * Create inclusive invariant for struct/class by aggregating
1146 * all the invariants in invs[].
1147 * void __invariant() const [pure nothrow @trusted]
1149 * invs[0](), invs[1](), ...;
1152 FuncDeclaration
*buildInv(AggregateDeclaration
*ad
, Scope
*sc
)
1154 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1155 Loc declLoc
= ad
->loc
;
1156 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
1158 switch (ad
->invs
.dim
)
1164 // Don't return invs[0] so it has uniquely generated name.
1168 Expression
*e
= NULL
;
1169 StorageClass stcx
= 0;
1170 for (size_t i
= 0; i
< ad
->invs
.dim
; i
++)
1172 stc
= mergeFuncAttrs(stc
, ad
->invs
[i
]);
1173 if (stc
& STCdisable
)
1177 StorageClass stcy
= (ad
->invs
[i
]->storage_class
& STCsynchronized
) |
1178 (ad
->invs
[i
]->type
->mod
& MODshared
? STCshared
: 0);
1181 else if (stcx
^ stcy
)
1183 #if 1 // currently rejects
1184 ad
->error(ad
->invs
[i
]->loc
, "mixing invariants with shared/synchronized differene is not supported");
1189 e
= Expression::combine(e
, new CallExp(loc
, new VarExp(loc
, ad
->invs
[i
], false)));
1191 InvariantDeclaration
*inv
;
1192 inv
= new InvariantDeclaration(declLoc
, Loc(), stc
| stcx
, Id::classInvariant
);
1193 inv
->fbody
= new ExpStatement(loc
, e
);
1194 ad
->members
->push(inv
);