2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
15 #include "aggregate.h"
18 #include "declaration.h"
21 #include "expression.h"
22 #include "statement.h"
26 /*******************************************
27 * We need an opAssign for the struct if
28 * it has a destructor or a postblit.
29 * We need to generate one if a user-specified one does not exist.
32 int StructDeclaration::needOpAssign()
35 if (X
) printf("StructDeclaration::needOpAssign() %s\n", toChars());
36 if (hasIdentityAssign
)
42 /* If any of the fields need an opAssign, then we
45 for (size_t i
= 0; i
< fields
.dim
; i
++)
47 Dsymbol
*s
= (Dsymbol
*)fields
.data
[i
];
48 VarDeclaration
*v
= s
->isVarDeclaration();
49 assert(v
&& v
->storage_class
& STCfield
);
50 Type
*tv
= v
->type
->toBasetype();
51 while (tv
->ty
== Tsarray
)
52 { TypeSArray
*ta
= (TypeSArray
*)tv
;
53 tv
= tv
->nextOf()->toBasetype();
55 if (tv
->ty
== Tstruct
)
56 { TypeStruct
*ts
= (TypeStruct
*)tv
;
57 StructDeclaration
*sd
= ts
->sym
;
58 if (sd
->needOpAssign())
63 if (X
) printf("\tdontneed\n");
67 if (X
) printf("\tneed\n");
72 /******************************************
73 * Build opAssign for struct.
74 * S* opAssign(S s) { ... }
77 FuncDeclaration
*StructDeclaration::buildOpAssign(Scope
*sc
)
82 //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
84 FuncDeclaration
*fop
= NULL
;
86 Argument
*param
= new Argument(STCnodtor
, type
, Id::p
, NULL
);
87 Arguments
*fparams
= new Arguments
;
89 Type
*ftype
= new TypeFunction(fparams
, handle
, FALSE
, LINKd
);
91 fop
= new FuncDeclaration(0, 0, Id::assign
, STCundefined
, ftype
);
96 * tmp = *this; *this = s; tmp.dtor();
98 //printf("\tswap copy\n");
99 Identifier
*idtmp
= Lexer::uniqueId("__tmp");
101 AssignExp
*ec
= NULL
;
104 tmp
= new VarDeclaration(0, type
, idtmp
, new VoidInitializer(0));
106 e
= new DeclarationExp(0, tmp
);
107 ec
= new AssignExp(0,
109 new PtrExp(0, new ThisExp(0)));
111 e
= Expression::combine(e
, ec
);
113 ec
= new AssignExp(0,
114 new PtrExp(0, new ThisExp(0)),
115 new IdentifierExp(0, Id::p
));
117 e
= Expression::combine(e
, ec
);
120 /* Instead of running the destructor on s, run it
121 * on tmp. This avoids needing to copy tmp back in to s.
123 Expression
*ec
= new DotVarExp(0, new VarExp(0, tmp
), dtor
, 0);
124 ec
= new CallExp(0, ec
);
125 e
= Expression::combine(e
, ec
);
129 { /* Do memberwise copy
131 //printf("\tmemberwise copy\n");
132 for (size_t i
= 0; i
< fields
.dim
; i
++)
134 Dsymbol
*s
= (Dsymbol
*)fields
.data
[i
];
135 VarDeclaration
*v
= s
->isVarDeclaration();
136 assert(v
&& v
->storage_class
& STCfield
);
138 AssignExp
*ec
= new AssignExp(0,
139 new DotVarExp(0, new ThisExp(0), v
, 0),
140 new DotVarExp(0, new IdentifierExp(0, Id::p
), v
, 0));
142 e
= Expression::combine(e
, ec
);
145 Statement
*s1
= new ExpStatement(0, e
);
151 Statement
*s2
= new ReturnStatement(0, e
);
153 fop
->fbody
= new CompoundStatement(0, s1
, s2
);
156 fop
->addMember(sc
, this, 1);
166 //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());
171 /*******************************************
172 * Build copy constructor for struct.
173 * Copy constructors are compiler generated only, and are only
174 * callable from the compiler. They are not user accessible.
175 * A copy constructor is:
176 * void cpctpr(ref S s)
182 * - postBlit() never sees uninitialized data
183 * - memcpy can be much more efficient than memberwise copy
184 * - no fields are overlooked
187 FuncDeclaration
*StructDeclaration::buildCpCtor(Scope
*sc
)
189 //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
190 FuncDeclaration
*fcp
= NULL
;
192 /* Copy constructor is only necessary if there is a postblit function,
193 * otherwise the code generator will just do a bit copy.
197 //printf("generating cpctor\n");
199 Argument
*param
= new Argument(STCref
, type
, Id::p
, NULL
);
200 Arguments
*fparams
= new Arguments
;
201 fparams
->push(param
);
202 Type
*ftype
= new TypeFunction(fparams
, Type::tvoid
, FALSE
, LINKd
);
204 fcp
= new FuncDeclaration(0, 0, Id::cpctor
, STCundefined
, ftype
);
207 Expression
*e
= new ThisExp(0);
208 e
= new PtrExp(0, e
);
209 AssignExp
*ea
= new AssignExp(0, e
, new IdentifierExp(0, Id::p
));
211 Statement
*s
= new ExpStatement(0, ea
);
214 e
= new VarExp(0, postblit
, 0);
215 e
= new CallExp(0, e
);
217 s
= new CompoundStatement(0, s
, new ExpStatement(0, e
));
234 /*****************************************
235 * Create inclusive postblit for struct by aggregating
236 * all the postblits in postblits[] with the postblits for
238 * Note the close similarity with AggregateDeclaration::buildDtor(),
239 * and the ordering changes (runs forward instead of backwards).
243 FuncDeclaration
*StructDeclaration::buildPostBlit(Scope
*sc
)
245 //printf("StructDeclaration::buildPostBlit() %s\n", toChars());
246 Expression
*e
= NULL
;
248 for (size_t i
= 0; i
< fields
.dim
; i
++)
250 Dsymbol
*s
= (Dsymbol
*)fields
.data
[i
];
251 VarDeclaration
*v
= s
->isVarDeclaration();
252 assert(v
&& v
->storage_class
& STCfield
);
253 Type
*tv
= v
->type
->toBasetype();
255 while (tv
->ty
== Tsarray
)
256 { TypeSArray
*ta
= (TypeSArray
*)tv
;
257 dim
*= ((TypeSArray
*)tv
)->dim
->toInteger();
258 tv
= tv
->nextOf()->toBasetype();
260 if (tv
->ty
== Tstruct
)
261 { TypeStruct
*ts
= (TypeStruct
*)tv
;
262 StructDeclaration
*sd
= ts
->sym
;
268 ex
= new DotVarExp(0, ex
, v
, 0);
272 ex
= new DotVarExp(0, ex
, sd
->postblit
, 0);
273 ex
= new CallExp(0, ex
);
277 // Typeinfo.postblit(cast(void*)&this.v);
278 Expression
*ea
= new AddrExp(0, ex
);
279 ea
= new CastExp(0, ea
, Type::tvoid
->pointerTo());
281 Expression
*et
= v
->type
->getTypeInfo(sc
);
282 et
= new DotIdExp(0, et
, Id::postblit
);
284 ex
= new CallExp(0, et
, ea
);
286 e
= Expression::combine(e
, ex
); // combine in forward order
291 /* Build our own "postblit" which executes e
294 { //printf("Building __fieldPostBlit()\n");
295 PostBlitDeclaration
*dd
= new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit"));
296 dd
->fbody
= new ExpStatement(0, e
);
302 switch (postblits
.dim
)
308 return (FuncDeclaration
*)postblits
.data
[0];
312 for (size_t i
= 0; i
< postblits
.dim
; i
++)
313 { FuncDeclaration
*fd
= (FuncDeclaration
*)postblits
.data
[i
];
314 Expression
*ex
= new ThisExp(0);
315 ex
= new DotVarExp(0, ex
, fd
, 0);
316 ex
= new CallExp(0, ex
);
317 e
= Expression::combine(e
, ex
);
319 PostBlitDeclaration
*dd
= new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit"));
320 dd
->fbody
= new ExpStatement(0, e
);
329 /*****************************************
330 * Create inclusive destructor for struct/class by aggregating
331 * all the destructors in dtors[] with the destructors for
333 * Note the close similarity with StructDeclaration::buildPostBlit(),
334 * and the ordering changes (runs backward instead of forwards).
337 FuncDeclaration
*AggregateDeclaration::buildDtor(Scope
*sc
)
339 //printf("AggregateDeclaration::buildDtor() %s\n", toChars());
340 Expression
*e
= NULL
;
343 for (size_t i
= 0; i
< fields
.dim
; i
++)
345 Dsymbol
*s
= (Dsymbol
*)fields
.data
[i
];
346 VarDeclaration
*v
= s
->isVarDeclaration();
347 assert(v
&& v
->storage_class
& STCfield
);
348 Type
*tv
= v
->type
->toBasetype();
350 while (tv
->ty
== Tsarray
)
351 { TypeSArray
*ta
= (TypeSArray
*)tv
;
352 dim
*= ((TypeSArray
*)tv
)->dim
->toInteger();
353 tv
= tv
->nextOf()->toBasetype();
355 if (tv
->ty
== Tstruct
)
356 { TypeStruct
*ts
= (TypeStruct
*)tv
;
357 StructDeclaration
*sd
= ts
->sym
;
363 ex
= new DotVarExp(0, ex
, v
, 0);
367 ex
= new DotVarExp(0, ex
, sd
->dtor
, 0);
368 ex
= new CallExp(0, ex
);
372 // Typeinfo.destroy(cast(void*)&this.v);
373 Expression
*ea
= new AddrExp(0, ex
);
374 ea
= new CastExp(0, ea
, Type::tvoid
->pointerTo());
376 Expression
*et
= v
->type
->getTypeInfo(sc
);
377 et
= new DotIdExp(0, et
, Id::destroy
);
379 ex
= new CallExp(0, et
, ea
);
381 e
= Expression::combine(ex
, e
); // combine in reverse order
386 /* Build our own "destructor" which executes e
389 { //printf("Building __fieldDtor()\n");
390 DtorDeclaration
*dd
= new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor"));
391 dd
->fbody
= new ExpStatement(0, e
);
404 return (FuncDeclaration
*)dtors
.data
[0];
408 for (size_t i
= 0; i
< dtors
.dim
; i
++)
409 { FuncDeclaration
*fd
= (FuncDeclaration
*)dtors
.data
[i
];
410 Expression
*ex
= new ThisExp(0);
411 ex
= new DotVarExp(0, ex
, fd
, 0);
412 ex
= new CallExp(0, ex
);
413 e
= Expression::combine(ex
, e
);
415 DtorDeclaration
*dd
= new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor"));
416 dd
->fbody
= new ExpStatement(0, e
);