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
11 #include "root/dsystem.h"
12 #include "root/root.h"
14 #include "aggregate.h"
17 #include "declaration.h"
20 #include "expression.h"
21 #include "statement.h"
26 Expression
*semantic(Expression
*e
, Scope
*sc
);
28 /*******************************************
29 * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
31 StorageClass
mergeFuncAttrs(StorageClass s1
, FuncDeclaration
*f
)
36 StorageClass s2
= (f
->storage_class
& STCdisable
);
37 TypeFunction
*tf
= (TypeFunction
*)f
->type
;
38 if (tf
->trust
== TRUSTsafe
)
40 else if (tf
->trust
== TRUSTsystem
)
42 else if (tf
->trust
== TRUSTtrusted
)
44 if (tf
->purity
!= PUREimpure
)
52 StorageClass sa
= s1
& s2
;
53 StorageClass so
= s1
| s2
;
57 else if (sa
& STCtrusted
)
59 else if ((so
& (STCtrusted
| STCsafe
)) == (STCtrusted
| STCsafe
))
61 else if (sa
& STCsafe
)
79 /*******************************************
80 * Check given aggregate actually has an identity opAssign or not.
82 * ad = struct or class
85 * if found, returns FuncDeclaration of opAssign, otherwise null
87 FuncDeclaration
*hasIdentityOpAssign(AggregateDeclaration
*ad
, Scope
*sc
)
89 Dsymbol
*assign
= search_function(ad
, Id::assign
);
92 /* check identity opAssign exists
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
;
100 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
106 FuncDeclaration
*f
= resolveFuncCall(ad
->loc
, sc
, assign
, NULL
, ad
->type
, &a
, 1);
110 f
= resolveFuncCall(ad
->loc
, sc
, assign
, NULL
, ad
->type
, &a
, 1);
114 global
.endGagging(errors
);
121 Parameters
*fparams
= f
->getParameters(&varargs
);
122 if (fparams
->dim
>= 1)
124 Parameter
*fparam0
= Parameter::getNth(fparams
, 0);
125 if (fparam0
->type
->toDsymbol(NULL
) != ad
)
129 // BUGS: This detection mechanism cannot find some opAssign-s like follows:
130 // struct S { void opAssign(ref immutable S) const; }
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.
141 bool needOpAssign(StructDeclaration
*sd
)
143 //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
144 if (sd
->isUnionDeclaration())
147 if (sd
->hasIdentityAssign
)
148 goto Lneed
; // because has identity==elaborate opAssign
150 if (sd
->dtor
|| sd
->postblit
)
153 /* If any of the fields need an opAssign, then we
156 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
158 VarDeclaration
*v
= sd
->fields
[i
];
159 if (v
->storage_class
& STCref
)
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
)
166 TypeStruct
*ts
= (TypeStruct
*)tv
;
167 if (ts
->sym
->isUnionDeclaration())
169 if (needOpAssign(ts
->sym
))
173 //printf("\tdontneed\n");
177 //printf("\tneed\n");
181 /******************************************
182 * Build opAssign for struct.
183 * ref S opAssign(S s) { ... }
185 * Note that s will be constructed onto the stack, and probably
186 * copy-constructed in caller site.
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
193 * Instead of running the destructor on s, run it on tmp instead.
195 * Otherwise, the body will make member-wise assignments:
197 * this.field1 = s.field1;
198 * this.field2 = s.field2;
201 FuncDeclaration
*buildOpAssign(StructDeclaration
*sd
, Scope
*sc
)
203 if (FuncDeclaration
*f
= hasIdentityOpAssign(sd
, sc
))
205 sd
->hasIdentityAssign
= true;
208 // Even if non-identity opAssign is defined, built-in identity opAssign
211 if (!needOpAssign(sd
))
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
219 // One of our sub-field might have `@disable opAssign` so we need to
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
++)
225 VarDeclaration
*v
= sd
->fields
[i
];
226 if (v
->storage_class
& STCref
)
230 Type
*tv
= v
->type
->baseElemOf();
231 if (tv
->ty
!= Tstruct
)
234 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
235 stc
= mergeFuncAttrs(stc
, hasIdentityOpAssign(sdv
, sc
));
238 if (sd
->dtor
|| sd
->postblit
)
240 if (!sd
->type
->isAssignable()) // Bugzilla 13044
242 stc
= mergeFuncAttrs(stc
, sd
->dtor
);
244 stc
= (stc
& ~STCsafe
) | STCtrusted
;
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
);
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
)
258 else if (sd
->dtor
|| sd
->postblit
)
260 /* Do swap this and rhs.
261 * __swap = this; this = s; __swap.dtor();
263 //printf("\tswap copy\n");
264 Identifier
*idtmp
= Identifier::generateId("__swap");
265 VarDeclaration
*tmp
= NULL
;
266 AssignExp
*ec
= NULL
;
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
);
275 ec
= new BlitExp(loc
, new ThisExp(loc
), new IdentifierExp(loc
, Id::p
));
276 e
= Expression::combine(e
, ec
);
279 /* Instead of running the destructor on s, run it
280 * on tmp. This avoids needing to copy tmp back in to s.
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
);
289 /* Do memberwise copy.
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.
296 //printf("\tmemberwise copy\n");
297 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
299 VarDeclaration
*v
= sd
->fields
[i
];
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
);
309 Statement
*s1
= new ExpStatement(loc
, e
);
314 e
= new ThisExp(loc
);
315 Statement
*s2
= new ReturnStatement(loc
, e
);
317 fop
->fbody
= new CompoundStatement(loc
, s1
, s2
);
321 sd
->members
->push(fop
);
322 fop
->addMember(sc
, sd
);
323 sd
->hasIdentityAssign
= true; // temporary mark identity assignable
325 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
326 Scope
*sc2
= sc
->push();
328 sc2
->linkage
= LINKd
;
332 // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
335 if (global
.endGagging(errors
)) // if errors happened
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
342 //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
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.
352 bool needOpEquals(StructDeclaration
*sd
)
354 //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
355 if (sd
->isUnionDeclaration())
358 if (sd
->hasIdentityEquals
)
361 /* If any of the fields has an opEquals, then we
364 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
366 VarDeclaration
*v
= sd
->fields
[i
];
367 if (v
->storage_class
& STCref
)
371 Type
*tv
= v
->type
->toBasetype();
372 Type
*tvbase
= tv
->baseElemOf();
373 if (tvbase
->ty
== Tstruct
)
375 TypeStruct
*ts
= (TypeStruct
*)tvbase
;
376 if (ts
->sym
->isUnionDeclaration())
378 if (needOpEquals(ts
->sym
))
380 if (ts
->sym
->aliasthis
) // Bugzilla 14806
383 if (tv
->isfloating())
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.
390 if (tv
->ty
== Tarray
)
392 if (tv
->ty
== Taarray
)
394 if (tv
->ty
== Tclass
)
398 //printf("\tdontneed\n");
402 //printf("\tneed\n");
406 /*******************************************
407 * Check given aggregate actually has an identity opEquals or not.
409 FuncDeclaration
*hasIdentityOpEquals(AggregateDeclaration
*ad
, Scope
*sc
)
411 Dsymbol
*eq
= search_function(ad
, Id::eq
);
414 /* check identity opEquals exists
416 UnionExp er
; new(&er
) NullExp(ad
->loc
, NULL
); // dummy rvalue
417 UnionExp el
; new(&el
) IdentifierExp(ad
->loc
, Id::p
); // dummy lvalue
420 for (size_t i
= 0; i
< 5; i
++)
422 Type
*tthis
= NULL
; // dead-store to prevent spurious warning
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;
432 FuncDeclaration
*f
= NULL
;
434 unsigned errors
= global
.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
439 for (size_t j
= 0; j
< 2; j
++)
441 a
[0] = (j
== 0 ? er
.exp() : el
.exp());
443 f
= resolveFuncCall(ad
->loc
, sc
, eq
, NULL
, tthis
, &a
, 1);
449 global
.endGagging(errors
);
462 /******************************************
463 * Build opEquals for struct.
464 * const bool opEquals(const S s) { ... }
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.
471 FuncDeclaration
*buildOpEquals(StructDeclaration
*sd
, Scope
*sc
)
473 if (hasIdentityOpEquals(sd
, sc
))
475 sd
->hasIdentityEquals
= true;
480 /******************************************
481 * Build __xopEquals for TypeInfo_Struct
482 * static bool __xopEquals(ref const S p, ref const S q)
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.
490 FuncDeclaration
*buildXopEquals(StructDeclaration
*sd
, Scope
*sc
)
492 if (!needOpEquals(sd
))
493 return NULL
; // bitwise comparison would work
495 //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
496 if (Dsymbol
*eq
= search_function(sd
, Id::eq
))
498 if (FuncDeclaration
*fd
= eq
->isFuncDeclaration())
500 TypeFunction
*tfeqptr
;
504 /* const bool opEquals(ref const S s);
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
);
512 fd
= fd
->overloadExactMatch(tfeqptr
);
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
);
526 Dsymbol
*s
= getDsymbol(e
);
528 sd
->xerreq
= s
->isFuncDeclaration();
531 Loc declLoc
= Loc(); // loc is unnecessary so __xopEquals is never called directly
532 Loc loc
= Loc(); // loc is unnecessary so errors are gagged
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
);
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
);
546 fop
->fbody
= new ReturnStatement(loc
, e
);
548 unsigned errors
= global
.startGagging(); // Do not report errors
549 Scope
*sc2
= sc
->push();
551 sc2
->linkage
= LINKd
;
557 if (global
.endGagging(errors
)) // if errors happened
563 /******************************************
564 * Build __xopCmp for TypeInfo_Struct
565 * static bool __xopCmp(ref const S p, ref const S q)
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.
573 FuncDeclaration
*buildXopCmp(StructDeclaration
*sd
, Scope
*sc
)
575 //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
576 if (Dsymbol
*cmp
= search_function(sd
, Id::cmp
))
578 if (FuncDeclaration
*fd
= cmp
->isFuncDeclaration())
580 TypeFunction
*tfcmpptr
;
584 /* const int opCmp(ref const S s);
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
);
592 fd
= fd
->overloadExactMatch(tfcmpptr
);
599 // FIXME: doesn't work for recursive alias this
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
);
611 Dsymbol
*s
= getDsymbol(e
);
613 sd
->xerrcmp
= s
->isFuncDeclaration();
616 Loc declLoc
= Loc(); // loc is unnecessary so __xopCmp is never called directly
617 Loc loc
= Loc(); // loc is unnecessary so errors are gagged
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
);
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
);
630 Expression
*e
= new CallExp(loc
, new DotIdExp(loc
, e1
, Id::cmp
), e2
);
632 Expression
*e
= new CallExp(loc
, new DotIdExp(loc
, e2
, Id::cmp
), e1
);
635 fop
->fbody
= new ReturnStatement(loc
, e
);
637 unsigned errors
= global
.startGagging(); // Do not report errors
638 Scope
*sc2
= sc
->push();
640 sc2
->linkage
= LINKd
;
646 if (global
.endGagging(errors
)) // if errors happened
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.
657 bool needToHash(StructDeclaration
*sd
)
659 //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
660 if (sd
->isUnionDeclaration())
666 /* If any of the fields has an opEquals, then we
669 for (size_t i
= 0; i
< sd
->fields
.dim
; i
++)
671 VarDeclaration
*v
= sd
->fields
[i
];
672 if (v
->storage_class
& STCref
)
676 Type
*tv
= v
->type
->toBasetype();
677 Type
*tvbase
= tv
->baseElemOf();
678 if (tvbase
->ty
== Tstruct
)
680 TypeStruct
*ts
= (TypeStruct
*)tvbase
;
681 if (ts
->sym
->isUnionDeclaration())
683 if (needToHash(ts
->sym
))
685 if (ts
->sym
->aliasthis
) // Bugzilla 14948
688 if (tv
->isfloating())
690 // This is necessray for:
691 // 1. comparison of +0.0 and -0.0 should be true.
694 if (tv
->ty
== Tarray
)
696 if (tv
->ty
== Taarray
)
698 if (tv
->ty
== Tclass
)
702 //printf("\tdontneed\n");
706 //printf("\tneed\n");
710 /******************************************
711 * Build __xtoHash for non-bitwise hashing
712 * static hash_t xtoHash(ref const S p) nothrow @trusted;
714 FuncDeclaration
*buildXtoHash(StructDeclaration
*sd
, Scope
*sc
)
716 if (Dsymbol
*s
= search_function(sd
, Id::tohash
))
718 static TypeFunction
*tftohash
;
721 tftohash
= new TypeFunction(NULL
, Type::thash_t
, 0, LINKd
);
722 tftohash
->mod
= MODconst
;
723 tftohash
= (TypeFunction
*)tftohash
->merge();
726 if (FuncDeclaration
*fd
= s
->isFuncDeclaration())
728 fd
= fd
->overloadExactMatch(tftohash
);
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
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
);
745 Identifier
*id
= Id::xtoHash
;
746 FuncDeclaration
*fop
= new FuncDeclaration(declLoc
, Loc(), id
, STCstatic
, tf
);
747 fop
->generated
= true;
749 /* Do memberwise hashing.
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().
756 "foreach (i, T; typeof(p.tupleof))"
757 " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
759 fop
->fbody
= new CompileStatement(loc
, new StringExp(loc
, const_cast<char *>(code
)));
761 Scope
*sc2
= sc
->push();
763 sc2
->linkage
= LINKd
;
770 //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
774 /*****************************************
775 * Create inclusive postblit for struct by aggregating
776 * all the postblits in postblits[] with the postblits for
778 * Note the close similarity with AggregateDeclaration::buildDtor(),
779 * and the ordering changes (runs forward instead of backwards).
781 FuncDeclaration
*buildPostBlit(StructDeclaration
*sd
, Scope
*sc
)
783 //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
784 if (sd
->isUnionDeclaration())
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
791 for (size_t i
= 0; i
< sd
->postblits
.dim
; i
++)
793 stc
|= sd
->postblits
[i
]->storage_class
& STCdisable
;
796 Statements
*a
= new Statements();
797 for (size_t i
= 0; i
< sd
->fields
.dim
&& !(stc
& STCdisable
); i
++)
799 VarDeclaration
*v
= sd
->fields
[i
];
800 if (v
->storage_class
& STCref
)
804 Type
*tv
= v
->type
->baseElemOf();
805 if (tv
->ty
!= Tstruct
)
807 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
810 assert(!sdv
->isUnionDeclaration());
811 sdv
->postblit
->functionSemantic();
813 stc
= mergeFuncAttrs(stc
, sdv
->postblit
);
814 stc
= mergeFuncAttrs(stc
, sdv
->dtor
);
815 if (stc
& STCdisable
)
821 Expression
*ex
= NULL
;
822 tv
= v
->type
->toBasetype();
823 if (tv
->ty
== Tstruct
)
825 // this.v.__xpostblit()
827 ex
= new ThisExp(loc
);
828 ex
= new DotVarExp(loc
, ex
, v
);
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
);
835 stc
= (stc
& ~STCsafe
) | STCtrusted
;
837 ex
= new DotVarExp(loc
, ex
, sdv
->postblit
, false);
838 ex
= new CallExp(loc
, ex
);
842 // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
845 while (tv
->ty
== Tsarray
)
847 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
848 tv
= tv
->nextOf()->toBasetype();
853 ex
= new ThisExp(loc
);
854 ex
= new DotVarExp(loc
, ex
, v
);
856 // This is a hack so we can call postblits on const/immutable objects.
857 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
858 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
860 stc
= (stc
& ~STCsafe
) | STCtrusted
;
862 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
863 new IntegerExp(loc
, n
, Type::tsize_t
));
864 // Prevent redundant bounds check
865 ((SliceExp
*)ex
)->upperIsInBounds
= true;
866 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
868 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayPostblit
), ex
);
870 a
->push(new ExpStatement(loc
, ex
)); // combine in forward order
872 /* Bugzilla 10972: When the following field postblit calls fail,
873 * this field should be destructed for Exception Safety.
877 sdv
->dtor
->functionSemantic();
879 tv
= v
->type
->toBasetype();
880 if (v
->type
->toBasetype()->ty
== Tstruct
)
884 ex
= new ThisExp(loc
);
885 ex
= new DotVarExp(loc
, ex
, v
);
887 // This is a hack so we can call destructors on const/immutable objects.
888 ex
= new AddrExp(loc
, ex
);
889 ex
= new CastExp(loc
, ex
, v
->type
->mutableOf()->pointerTo());
890 ex
= new PtrExp(loc
, ex
);
892 stc
= (stc
& ~STCsafe
) | STCtrusted
;
894 ex
= new DotVarExp(loc
, ex
, sdv
->dtor
, false);
895 ex
= new CallExp(loc
, ex
);
899 // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
902 while (tv
->ty
== Tsarray
)
904 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
905 tv
= tv
->nextOf()->toBasetype();
910 ex
= new ThisExp(loc
);
911 ex
= new DotVarExp(loc
, ex
, v
);
913 // This is a hack so we can call destructors on const/immutable objects.
914 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
915 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
917 stc
= (stc
& ~STCsafe
) | STCtrusted
;
919 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
920 new IntegerExp(loc
, n
, Type::tsize_t
));
921 // Prevent redundant bounds check
922 ((SliceExp
*)ex
)->upperIsInBounds
= true;
923 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
925 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayDtor
), ex
);
927 a
->push(new OnScopeStatement(loc
, TOKon_scope_failure
, new ExpStatement(loc
, ex
)));
930 // Build our own "postblit" which executes a, but only if needed.
931 if (a
->dim
|| (stc
& STCdisable
))
933 //printf("Building __fieldPostBlit()\n");
934 PostBlitDeclaration
*dd
= new PostBlitDeclaration(declLoc
, Loc(), stc
, Id::__fieldPostblit
);
935 dd
->generated
= true;
936 dd
->storage_class
|= STCinference
;
937 dd
->fbody
= (stc
& STCdisable
) ? NULL
: new CompoundStatement(loc
, a
);
938 sd
->postblits
.shift(dd
);
939 sd
->members
->push(dd
);
943 FuncDeclaration
*xpostblit
= NULL
;
944 switch (sd
->postblits
.dim
)
950 xpostblit
= sd
->postblits
[0];
954 Expression
*e
= NULL
;
955 stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
956 for (size_t i
= 0; i
< sd
->postblits
.dim
; i
++)
958 FuncDeclaration
*fd
= sd
->postblits
[i
];
959 stc
= mergeFuncAttrs(stc
, fd
);
960 if (stc
& STCdisable
)
965 Expression
*ex
= new ThisExp(loc
);
966 ex
= new DotVarExp(loc
, ex
, fd
, false);
967 ex
= new CallExp(loc
, ex
);
968 e
= Expression::combine(e
, ex
);
970 PostBlitDeclaration
*dd
= new PostBlitDeclaration(declLoc
, Loc(), stc
, Id::__aggrPostblit
);
971 dd
->storage_class
|= STCinference
;
972 dd
->fbody
= new ExpStatement(loc
, e
);
973 sd
->members
->push(dd
);
978 // Add an __xpostblit alias to make the inclusive postblit accessible
981 AliasDeclaration
*alias
= new AliasDeclaration(Loc(), Id::__xpostblit
, xpostblit
);
983 sd
->members
->push(alias
);
984 alias
->addMember(sc
, sd
); // add to symbol table
989 /*****************************************
990 * Create inclusive destructor for struct/class by aggregating
991 * all the destructors in dtors[] with the destructors for
993 * Note the close similarity with StructDeclaration::buildPostBlit(),
994 * and the ordering changes (runs backward instead of forwards).
996 FuncDeclaration
*buildDtor(AggregateDeclaration
*ad
, Scope
*sc
)
998 //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
999 if (ad
->isUnionDeclaration())
1002 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1003 Loc declLoc
= ad
->dtors
.dim
? ad
->dtors
[0]->loc
: ad
->loc
;
1004 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
1006 Expression
*e
= NULL
;
1007 for (size_t i
= 0; i
< ad
->fields
.dim
; i
++)
1009 VarDeclaration
*v
= ad
->fields
[i
];
1010 if (v
->storage_class
& STCref
)
1014 Type
*tv
= v
->type
->baseElemOf();
1015 if (tv
->ty
!= Tstruct
)
1017 StructDeclaration
*sdv
= ((TypeStruct
*)tv
)->sym
;
1020 sdv
->dtor
->functionSemantic();
1022 stc
= mergeFuncAttrs(stc
, sdv
->dtor
);
1023 if (stc
& STCdisable
)
1029 Expression
*ex
= NULL
;
1030 tv
= v
->type
->toBasetype();
1031 if (tv
->ty
== Tstruct
)
1035 ex
= new ThisExp(loc
);
1036 ex
= new DotVarExp(loc
, ex
, v
);
1038 // This is a hack so we can call destructors on const/immutable objects.
1039 ex
= new AddrExp(loc
, ex
);
1040 ex
= new CastExp(loc
, ex
, v
->type
->mutableOf()->pointerTo());
1041 ex
= new PtrExp(loc
, ex
);
1043 stc
= (stc
& ~STCsafe
) | STCtrusted
;
1045 ex
= new DotVarExp(loc
, ex
, sdv
->dtor
, false);
1046 ex
= new CallExp(loc
, ex
);
1050 // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
1053 while (tv
->ty
== Tsarray
)
1055 n
*= ((TypeSArray
*)tv
)->dim
->toUInteger();
1056 tv
= tv
->nextOf()->toBasetype();
1061 ex
= new ThisExp(loc
);
1062 ex
= new DotVarExp(loc
, ex
, v
);
1064 // This is a hack so we can call destructors on const/immutable objects.
1065 ex
= new DotIdExp(loc
, ex
, Id::ptr
);
1066 ex
= new CastExp(loc
, ex
, sdv
->type
->pointerTo());
1068 stc
= (stc
& ~STCsafe
) | STCtrusted
;
1070 ex
= new SliceExp(loc
, ex
, new IntegerExp(loc
, 0, Type::tsize_t
),
1071 new IntegerExp(loc
, n
, Type::tsize_t
));
1072 // Prevent redundant bounds check
1073 ((SliceExp
*)ex
)->upperIsInBounds
= true;
1074 ((SliceExp
*)ex
)->lowerIsLessThanUpper
= true;
1076 ex
= new CallExp(loc
, new IdentifierExp(loc
, Id::_ArrayDtor
), ex
);
1078 e
= Expression::combine(ex
, e
); // combine in reverse order
1081 /* Build our own "destructor" which executes e
1083 if (e
|| (stc
& STCdisable
))
1085 //printf("Building __fieldDtor()\n");
1086 DtorDeclaration
*dd
= new DtorDeclaration(declLoc
, Loc(), stc
, Id::__fieldDtor
);
1087 dd
->generated
= true;
1088 dd
->storage_class
|= STCinference
;
1089 dd
->fbody
= new ExpStatement(loc
, e
);
1090 ad
->dtors
.shift(dd
);
1091 ad
->members
->push(dd
);
1095 FuncDeclaration
*xdtor
= NULL
;
1096 switch (ad
->dtors
.dim
)
1102 xdtor
= ad
->dtors
[0];
1107 stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1108 for (size_t i
= 0; i
< ad
->dtors
.dim
; i
++)
1110 FuncDeclaration
*fd
= ad
->dtors
[i
];
1111 stc
= mergeFuncAttrs(stc
, fd
);
1112 if (stc
& STCdisable
)
1117 Expression
*ex
= new ThisExp(loc
);
1118 ex
= new DotVarExp(loc
, ex
, fd
, false);
1119 ex
= new CallExp(loc
, ex
);
1120 e
= Expression::combine(ex
, e
);
1122 DtorDeclaration
*dd
= new DtorDeclaration(declLoc
, Loc(), stc
, Id::__aggrDtor
);
1123 dd
->generated
= true;
1124 dd
->storage_class
|= STCinference
;
1125 dd
->fbody
= new ExpStatement(loc
, e
);
1126 ad
->members
->push(dd
);
1131 // Add an __xdtor alias to make the inclusive dtor accessible
1134 AliasDeclaration
*alias
= new AliasDeclaration(Loc(), Id::__xdtor
, xdtor
);
1135 alias
->semantic(sc
);
1136 ad
->members
->push(alias
);
1137 alias
->addMember(sc
, ad
); // add to symbol table
1142 /******************************************
1143 * Create inclusive invariant for struct/class by aggregating
1144 * all the invariants in invs[].
1145 * void __invariant() const [pure nothrow @trusted]
1147 * invs[0](), invs[1](), ...;
1150 FuncDeclaration
*buildInv(AggregateDeclaration
*ad
, Scope
*sc
)
1152 StorageClass stc
= STCsafe
| STCnothrow
| STCpure
| STCnogc
;
1153 Loc declLoc
= ad
->loc
;
1154 Loc loc
= Loc(); // internal code should have no loc to prevent coverage
1156 switch (ad
->invs
.dim
)
1162 // Don't return invs[0] so it has uniquely generated name.
1166 Expression
*e
= NULL
;
1167 StorageClass stcx
= 0;
1168 for (size_t i
= 0; i
< ad
->invs
.dim
; i
++)
1170 stc
= mergeFuncAttrs(stc
, ad
->invs
[i
]);
1171 if (stc
& STCdisable
)
1175 StorageClass stcy
= (ad
->invs
[i
]->storage_class
& STCsynchronized
) |
1176 (ad
->invs
[i
]->type
->mod
& MODshared
? STCshared
: 0);
1179 else if (stcx
^ stcy
)
1181 #if 1 // currently rejects
1182 ad
->error(ad
->invs
[i
]->loc
, "mixing invariants with shared/synchronized differene is not supported");
1187 e
= Expression::combine(e
, new CallExp(loc
, new VarExp(loc
, ad
->invs
[i
], false)));
1189 InvariantDeclaration
*inv
;
1190 inv
= new InvariantDeclaration(declLoc
, Loc(), stc
| stcx
, Id::classInvariant
);
1191 inv
->fbody
= new ExpStatement(loc
, e
);
1192 ad
->members
->push(inv
);