0
|
1 module dmd.StructDeclaration;
|
|
2
|
|
3 import dmd.AggregateDeclaration;
|
|
4 import dmd.FuncDeclaration;
|
|
5 import dmd.DeclarationExp;
|
|
6 import dmd.VoidInitializer;
|
|
7 import dmd.Initializer;
|
|
8 import dmd.ExpInitializer;
|
|
9 import dmd.TOK;
|
|
10 import dmd.Statement;
|
|
11 import dmd.VarExp;
|
|
12 import dmd.CompoundStatement;
|
|
13 import dmd.AssignExp;
|
|
14 import dmd.DotVarExp;
|
|
15 import dmd.AddrExp;
|
|
16 import dmd.CastExp;
|
|
17 import dmd.PostBlitDeclaration;
|
|
18 import dmd.Lexer;
|
|
19 import dmd.ExpStatement;
|
|
20 import dmd.DotIdExp;
|
|
21 import dmd.TypeSArray;
|
|
22 import dmd.ThisExp;
|
|
23 import dmd.ThisDeclaration;
|
|
24 import dmd.TypeFunction;
|
|
25 import dmd.Argument;
|
|
26 import dmd.Id;
|
|
27 import dmd.TY;
|
|
28 import dmd.LINK;
|
|
29 import dmd.Type;
|
|
30 import dmd.DsymbolTable;
|
|
31 import dmd.ArrayTypes;
|
|
32 import dmd.Loc;
|
|
33 import dmd.STC;
|
|
34 import dmd.Identifier;
|
|
35 import dmd.TemplateInstance;
|
|
36 import dmd.Dsymbol;
|
|
37 import dmd.Scope;
|
|
38 import dmd.OutBuffer;
|
|
39 import dmd.HdrGenState;
|
|
40 import dmd.PROT;
|
|
41 import dmd.TypeStruct;
|
|
42 import dmd.expression.Util;
|
|
43 import dmd.Expression;
|
|
44 import dmd.IdentifierExp;
|
|
45 import dmd.PtrExp;
|
|
46 import dmd.CallExp;
|
|
47 import dmd.ReturnStatement;
|
|
48 import dmd.ScopeDsymbol;
|
|
49 import dmd.Module;
|
|
50 import dmd.VarDeclaration;
|
|
51 import dmd.InvariantDeclaration;
|
|
52 import dmd.NewDeclaration;
|
|
53 import dmd.DeleteDeclaration;
|
|
54 import dmd.Global;
|
|
55
|
|
56 import dmd.backend.dt_t;
|
|
57 import dmd.backend.Util;
|
|
58 import dmd.backend.SC;
|
|
59 import dmd.backend.DT;
|
|
60 import dmd.backend.FL;
|
|
61 import dmd.backend.glue;
|
|
62
|
|
63 class StructDeclaration : AggregateDeclaration
|
|
64 {
|
|
65 bool zeroInit; // true if initialize with 0 fill
|
|
66
|
|
67 version (DMDV2) {
|
|
68 int hasIdentityAssign; // !=0 if has identity opAssign
|
|
69 FuncDeclaration cpctor; // generated copy-constructor, if any
|
|
70
|
|
71 FuncDeclarations postblits; // Array of postblit functions
|
|
72 FuncDeclaration postblit; // aggregate postblit
|
|
73 }
|
|
74
|
|
75 this(Loc loc, Identifier id)
|
|
76 {
|
|
77 super(loc, id);
|
|
78
|
|
79 // For forward references
|
|
80 type = new TypeStruct(this);
|
|
81
|
|
82 postblits = new FuncDeclarations(); ///
|
|
83 }
|
|
84
|
|
85 Dsymbol syntaxCopy(Dsymbol s)
|
|
86 {
|
|
87 assert(false);
|
|
88 }
|
|
89
|
|
90 void semantic(Scope sc)
|
|
91 {
|
|
92 int i;
|
|
93 Scope sc2;
|
|
94
|
|
95 //printf("+StructDeclaration.semantic(this=%p, '%s')\n", this, toChars());
|
|
96
|
|
97 //static int count; if (++count == 20) *(char*)0=0;
|
|
98
|
|
99 assert(type);
|
|
100 if (!members) // if forward reference
|
|
101 return;
|
|
102
|
|
103 if (symtab)
|
|
104 { if (!scope_)
|
|
105 return; // semantic() already completed
|
|
106 }
|
|
107 else
|
|
108 symtab = new DsymbolTable();
|
|
109
|
|
110 Scope scx = null;
|
|
111 if (scope_)
|
|
112 { sc = scope_;
|
|
113 scx = scope_; // save so we don't make redundant copies
|
|
114 scope_ = null;
|
|
115 }
|
|
116
|
|
117 parent = sc.parent;
|
|
118 type = type.semantic(loc, sc);
|
|
119 version (STRUCTTHISREF) {
|
|
120 handle = type;
|
|
121 } else {
|
|
122 handle = type.pointerTo();
|
|
123 }
|
|
124 structalign = sc.structalign;
|
|
125 protection = sc.protection;
|
|
126 storage_class |= sc.stc;
|
|
127 if (sc.stc & STC.STCdeprecated)
|
|
128 isdeprecated = 1;
|
|
129 assert(!isAnonymous());
|
|
130 if (sc.stc & STC.STCabstract)
|
|
131 error("structs, unions cannot be abstract");
|
|
132 version (DMDV2) {
|
|
133 if (storage_class & STC.STCimmutable)
|
|
134 type = type.invariantOf();
|
|
135 else if (storage_class & STC.STCconst)
|
|
136 type = type.constOf();
|
|
137 else if (storage_class & STC.STCshared)
|
|
138 type = type.sharedOf();
|
|
139 }
|
|
140
|
|
141 if (sizeok == 0) // if not already done the addMember step
|
|
142 {
|
|
143 int hasfunctions = 0;
|
|
144 for (i = 0; i < members.dim; i++)
|
|
145 {
|
|
146 Dsymbol s = cast(Dsymbol)members.data[i];
|
|
147 //printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars());
|
13
|
148 s.addMember(sc, this, true);
|
0
|
149 if (s.isFuncDeclaration())
|
|
150 hasfunctions = 1;
|
|
151 }
|
|
152
|
|
153 // If nested struct, add in hidden 'this' pointer to outer scope
|
|
154 if (hasfunctions && !(storage_class & STC.STCstatic))
|
|
155 { Dsymbol s = toParent2();
|
|
156 if (s)
|
|
157 {
|
|
158 AggregateDeclaration ad = s.isAggregateDeclaration();
|
|
159 FuncDeclaration fd = s.isFuncDeclaration();
|
|
160
|
|
161 TemplateInstance ti;
|
|
162 if (ad && (ti = ad.parent.isTemplateInstance()) !is null && ti.isnested || fd)
|
|
163 { isnested = true;
|
|
164 Type t;
|
|
165 if (ad)
|
|
166 t = ad.handle;
|
|
167 else if (fd)
|
|
168 {
|
|
169 AggregateDeclaration add = fd.isMember2();
|
|
170 if (add)
|
|
171 t = add.handle;
|
|
172 else
|
|
173 t = Type.tvoidptr;
|
|
174 }
|
|
175 else
|
|
176 assert(0);
|
|
177 if (t.ty == TY.Tstruct)
|
|
178 t = Type.tvoidptr; // t should not be a ref type
|
|
179 assert(!vthis);
|
|
180 vthis = new ThisDeclaration(loc, t);
|
|
181 //vthis.storage_class |= STC.STCref;
|
|
182 members.push(cast(void*)vthis);
|
|
183 }
|
|
184 }
|
|
185 }
|
|
186 }
|
|
187
|
|
188 sizeok = 0;
|
|
189 sc2 = sc.push(this);
|
|
190 sc2.stc &= storage_class & STC.STC_TYPECTOR;
|
|
191 sc2.parent = this;
|
|
192 if (isUnionDeclaration())
|
|
193 sc2.inunion = 1;
|
|
194 sc2.protection = PROT.PROTpublic;
|
|
195 sc2.explicitProtection = 0;
|
|
196
|
|
197 int members_dim = members.dim;
|
|
198 for (i = 0; i < members_dim; i++)
|
|
199 {
|
|
200 Dsymbol s = cast(Dsymbol)members.data[i];
|
|
201 s.semantic(sc2);
|
|
202 if (isUnionDeclaration())
|
|
203 sc2.offset = 0;
|
|
204 static if (false) {
|
|
205 if (sizeok == 2)
|
|
206 { //printf("forward reference\n");
|
|
207 break;
|
|
208 }
|
|
209 }
|
|
210 Type t;
|
|
211 if (s.isDeclaration() &&
|
|
212 (t = s.isDeclaration().type) !is null &&
|
|
213 t.toBasetype().ty == TY.Tstruct)
|
|
214 { StructDeclaration sd = cast(StructDeclaration)t.toDsymbol(sc);
|
|
215 if (sd.isnested)
|
|
216 error("inner struct %s cannot be a field", sd.toChars());
|
|
217 }
|
|
218 }
|
|
219
|
|
220 /* The TypeInfo_Struct is expecting an opEquals and opCmp with
|
|
221 * a parameter that is a pointer to the struct. But if there
|
|
222 * isn't one, but is an opEquals or opCmp with a value, write
|
|
223 * another that is a shell around the value:
|
|
224 * int opCmp(struct *p) { return opCmp(*p); }
|
|
225 */
|
|
226
|
|
227 TypeFunction tfeqptr;
|
|
228 {
|
|
229 Arguments arguments = new Arguments;
|
|
230 Argument arg = new Argument(STC.STCin, handle, Id.p, null);
|
|
231
|
|
232 arguments.push(cast(void*)arg);
|
|
233 tfeqptr = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd);
|
|
234 tfeqptr = cast(TypeFunction)tfeqptr.semantic(Loc(0), sc);
|
|
235 }
|
|
236
|
|
237 TypeFunction tfeq;
|
|
238 {
|
|
239 Arguments arguments = new Arguments;
|
|
240 Argument arg = new Argument(STC.STCin, type, null, null);
|
|
241
|
|
242 arguments.push(cast(void*)arg);
|
|
243 tfeq = new TypeFunction(arguments, Type.tint32, 0, LINK.LINKd);
|
|
244 tfeq = cast(TypeFunction)tfeq.semantic(Loc(0), sc);
|
|
245 }
|
|
246
|
|
247 Identifier id = Id.eq;
|
|
248 for (int j = 0; j < 2; j++)
|
|
249 {
|
|
250 Dsymbol s = search_function(this, id);
|
|
251 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
|
|
252 if (fdx)
|
|
253 { FuncDeclaration fd = fdx.overloadExactMatch(tfeqptr);
|
|
254 if (!fd)
|
|
255 { fd = fdx.overloadExactMatch(tfeq);
|
|
256 if (fd)
|
|
257 { // Create the thunk, fdptr
|
|
258 FuncDeclaration fdptr = new FuncDeclaration(loc, loc, fdx.ident, STC.STCundefined, tfeqptr);
|
|
259 Expression e = new IdentifierExp(loc, Id.p);
|
|
260 e = new PtrExp(loc, e);
|
|
261 Expressions args = new Expressions();
|
|
262 args.push(cast(void*)e);
|
|
263 e = new IdentifierExp(loc, id);
|
|
264 e = new CallExp(loc, e, args);
|
|
265 fdptr.fbody = new ReturnStatement(loc, e);
|
|
266 ScopeDsymbol ss = fdx.parent.isScopeDsymbol();
|
|
267 assert(ss);
|
|
268 ss.members.push(cast(void*)fdptr);
|
13
|
269 fdptr.addMember(sc, ss, true);
|
0
|
270 fdptr.semantic(sc2);
|
|
271 }
|
|
272 }
|
|
273 }
|
|
274
|
|
275 id = Id.cmp;
|
|
276 }
|
|
277 version (DMDV2) {
|
|
278 dtor = buildDtor(sc2);
|
|
279 postblit = buildPostBlit(sc2);
|
|
280 cpctor = buildCpCtor(sc2);
|
|
281 buildOpAssign(sc2);
|
|
282 }
|
|
283
|
|
284 sc2.pop();
|
|
285
|
|
286 if (sizeok == 2)
|
|
287 { // semantic() failed because of forward references.
|
|
288 // Unwind what we did, and defer it for later
|
|
289 fields.setDim(0);
|
|
290 structsize = 0;
|
|
291 alignsize = 0;
|
|
292 structalign = 0;
|
|
293
|
|
294 scope_ = scx ? scx : new Scope(sc);
|
|
295 scope_.setNoFree();
|
|
296 scope_.module_.addDeferredSemantic(this);
|
|
297 //printf("\tdeferring %s\n", toChars());
|
|
298 return;
|
|
299 }
|
|
300
|
|
301 // 0 sized struct's are set to 1 byte
|
|
302 if (structsize == 0)
|
|
303 {
|
|
304 structsize = 1;
|
|
305 alignsize = 1;
|
|
306 }
|
|
307
|
|
308 // Round struct size up to next alignsize boundary.
|
|
309 // This will ensure that arrays of structs will get their internals
|
|
310 // aligned properly.
|
|
311 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
|
|
312
|
|
313 sizeok = 1;
|
|
314 Module.dprogress++;
|
|
315
|
|
316 //printf("-StructDeclaration.semantic(this=%p, '%s')\n", this, toChars());
|
|
317
|
|
318 // Determine if struct is all zeros or not
|
|
319 zeroInit = true;
|
|
320 for (i = 0; i < fields.dim; i++)
|
|
321 {
|
|
322 Dsymbol s = cast(Dsymbol)fields.data[i];
|
|
323 VarDeclaration vd = s.isVarDeclaration();
|
|
324 if (vd && !vd.isDataseg())
|
|
325 {
|
|
326 if (vd.init)
|
|
327 {
|
|
328 // Should examine init to see if it is really all 0's
|
|
329 zeroInit = false;
|
|
330 break;
|
|
331 }
|
|
332 else
|
|
333 {
|
|
334 if (!vd.type.isZeroInit(loc))
|
|
335 {
|
|
336 zeroInit = false;
|
|
337 break;
|
|
338 }
|
|
339 }
|
|
340 }
|
|
341 }
|
|
342
|
|
343 /* Look for special member functions.
|
|
344 */
|
|
345 version (DMDV2) {
|
|
346 ctor = search(Loc(0), Id.ctor, 0);
|
|
347 }
|
|
348 inv = cast(InvariantDeclaration)search(Loc(0), Id.classInvariant, 0);
|
|
349 aggNew = cast(NewDeclaration)search(Loc(0), Id.classNew, 0);
|
|
350 aggDelete = cast(DeleteDeclaration)search(Loc(0), Id.classDelete, 0);
|
|
351
|
|
352 if (sc.func)
|
|
353 {
|
|
354 semantic2(sc);
|
|
355 semantic3(sc);
|
|
356 }
|
|
357 }
|
|
358
|
|
359 void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
360 {
|
|
361 assert(false);
|
|
362 }
|
|
363
|
|
364 string mangle()
|
|
365 {
|
|
366 //printf("StructDeclaration.mangle() '%s'\n", toChars());
|
|
367 return Dsymbol.mangle();
|
|
368 }
|
|
369
|
|
370 string kind()
|
|
371 {
|
|
372 assert(false);
|
|
373 }
|
|
374
|
|
375 /*******************************************
|
|
376 * We need an opAssign for the struct if
|
|
377 * it has a destructor or a postblit.
|
|
378 * We need to generate one if a user-specified one does not exist.
|
|
379 */
|
|
380 bool needOpAssign()
|
|
381 {
|
|
382 static if (false) {
|
|
383 printf("StructDeclaration.needOpAssign() %s\n", toChars());
|
|
384 }
|
|
385 if (hasIdentityAssign)
|
|
386 goto Ldontneed;
|
|
387
|
|
388 if (dtor || postblit)
|
|
389 goto Lneed;
|
|
390
|
|
391 /* If any of the fields need an opAssign, then we
|
|
392 * need it too.
|
|
393 */
|
|
394 for (size_t i = 0; i < fields.dim; i++)
|
|
395 {
|
|
396 Dsymbol s = cast(Dsymbol)fields.data[i];
|
|
397 VarDeclaration v = s.isVarDeclaration();
|
|
398 assert(v && v.storage_class & STC.STCfield);
|
|
399 if (v.storage_class & STC.STCref)
|
|
400 continue;
|
|
401 Type tv = v.type.toBasetype();
|
|
402 while (tv.ty == TY.Tsarray)
|
|
403 { TypeSArray ta = cast(TypeSArray)tv;
|
|
404 tv = tv.nextOf().toBasetype();
|
|
405 }
|
|
406 if (tv.ty == TY.Tstruct)
|
|
407 { TypeStruct ts = cast(TypeStruct)tv;
|
|
408 StructDeclaration sd = ts.sym;
|
|
409 if (sd.needOpAssign())
|
|
410 goto Lneed;
|
|
411 }
|
|
412 }
|
|
413 Ldontneed:
|
|
414 static if (false) {
|
|
415 printf("\tdontneed\n");
|
|
416 }
|
|
417 return false;
|
|
418
|
|
419 Lneed:
|
|
420 static if (false) {
|
|
421 printf("\tneed\n");
|
|
422 }
|
|
423 return true;
|
|
424 }
|
|
425
|
|
426 /******************************************
|
|
427 * Build opAssign for struct.
|
|
428 * S* opAssign(S s) { ... }
|
|
429 */
|
|
430 FuncDeclaration buildOpAssign(Scope sc)
|
|
431 {
|
|
432 if (!needOpAssign())
|
|
433 return null;
|
|
434
|
|
435 //printf("StructDeclaration.buildOpAssign() %s\n", toChars());
|
|
436
|
|
437 FuncDeclaration fop = null;
|
|
438
|
|
439 Argument param = new Argument(STC.STCnodtor, type, Id.p, null);
|
|
440 Arguments fparams = new Arguments;
|
|
441 fparams.push(cast(void*)param);
|
|
442 Type ftype = new TypeFunction(fparams, handle, false, LINK.LINKd);
|
|
443 version (STRUCTTHISREF) {
|
|
444 (cast(TypeFunction)ftype).isref = 1;
|
|
445 }
|
|
446
|
|
447 fop = new FuncDeclaration(Loc(0), Loc(0), Id.assign, STC.STCundefined, ftype);
|
|
448
|
|
449 Expression e = null;
|
|
450 if (postblit)
|
|
451 { /* Swap:
|
|
452 * tmp = *this; *this = s; tmp.dtor();
|
|
453 */
|
|
454 //printf("\tswap copy\n");
|
|
455 Identifier idtmp = Lexer.uniqueId("__tmp");
|
|
456 VarDeclaration tmp;
|
|
457 AssignExp ec = null;
|
|
458 if (dtor)
|
|
459 {
|
|
460 tmp = new VarDeclaration(Loc(0), type, idtmp, new VoidInitializer(Loc(0)));
|
|
461 tmp.noauto = true;
|
|
462 e = new DeclarationExp(Loc(0), tmp);
|
|
463
|
|
464 Expression e2;
|
|
465 version (STRUCTTHISREF) {
|
|
466 e2 = new ThisExp(Loc(0));
|
|
467 } else {
|
|
468 e2 = new PtrExp(Loc(0), new ThisExp(Loc(0)));
|
|
469 }
|
|
470 ec = new AssignExp(Loc(0), new VarExp(Loc(0), tmp), e2);
|
|
471 ec.op = TOK.TOKblit;
|
|
472 e = Expression.combine(e, ec);
|
|
473 }
|
|
474 Expression e2;
|
|
475 version (STRUCTTHISREF) {
|
|
476 e2 = new ThisExp(Loc(0));
|
|
477 } else {
|
|
478 e2 = new PtrExp(Loc(0), new ThisExp(Loc(0)));
|
|
479 }
|
|
480
|
|
481 ec = new AssignExp(Loc(0), e2, new IdentifierExp(Loc(0), Id.p));
|
|
482 ec.op = TOK.TOKblit;
|
|
483 e = Expression.combine(e, ec);
|
|
484 if (dtor)
|
|
485 {
|
|
486 /* Instead of running the destructor on s, run it
|
|
487 * on tmp. This avoids needing to copy tmp back in to s.
|
|
488 */
|
|
489 Expression ecc = new DotVarExp(Loc(0), new VarExp(Loc(0), tmp), dtor, 0);
|
|
490 ecc = new CallExp(Loc(0), ecc);
|
|
491 e = Expression.combine(e, ecc);
|
|
492 }
|
|
493 }
|
|
494 else
|
|
495 { /* Do memberwise copy
|
|
496 */
|
|
497 //printf("\tmemberwise copy\n");
|
|
498 for (size_t i = 0; i < fields.dim; i++)
|
|
499 {
|
|
500 Dsymbol s = cast(Dsymbol)fields.data[i];
|
|
501 VarDeclaration v = s.isVarDeclaration();
|
|
502 assert(v && v.storage_class & STC.STCfield);
|
|
503 // this.v = s.v;
|
|
504 AssignExp ec = new AssignExp(Loc(0), new DotVarExp(Loc(0), new ThisExp(Loc(0)), v, 0), new DotVarExp(Loc(0), new IdentifierExp(Loc(0), Id.p), v, 0));
|
|
505 ec.op = TOK.TOKblit;
|
|
506 e = Expression.combine(e, ec);
|
|
507 }
|
|
508 }
|
|
509 Statement s1 = new ExpStatement(Loc(0), e);
|
|
510
|
|
511 /* Add:
|
|
512 * return this;
|
|
513 */
|
|
514 e = new ThisExp(Loc(0));
|
|
515 Statement s2 = new ReturnStatement(Loc(0), e);
|
|
516
|
|
517 fop.fbody = new CompoundStatement(Loc(0), s1, s2);
|
|
518
|
|
519 members.push(cast(void*)fop);
|
13
|
520 fop.addMember(sc, this, true);
|
0
|
521
|
|
522 sc = sc.push();
|
|
523 sc.stc = STC.STCundefined;
|
|
524 sc.linkage = LINK.LINKd;
|
|
525
|
|
526 fop.semantic(sc);
|
|
527
|
|
528 sc.pop();
|
|
529
|
|
530 //printf("-StructDeclaration.buildOpAssign() %s\n", toChars());
|
|
531
|
|
532 return fop;
|
|
533 }
|
|
534
|
|
535 /*****************************************
|
|
536 * Create inclusive postblit for struct by aggregating
|
|
537 * all the postblits in postblits[] with the postblits for
|
|
538 * all the members.
|
|
539 * Note the close similarity with AggregateDeclaration.buildDtor(),
|
|
540 * and the ordering changes (runs forward instead of backwards).
|
|
541 */
|
|
542
|
|
543 version (DMDV2) {
|
|
544 FuncDeclaration buildPostBlit(Scope sc)
|
|
545 {
|
|
546 //printf("StructDeclaration.buildPostBlit() %s\n", toChars());
|
|
547 Expression e = null;
|
|
548
|
|
549 for (size_t i = 0; i < fields.dim; i++)
|
|
550 {
|
|
551 Dsymbol s = cast(Dsymbol)fields.data[i];
|
|
552 VarDeclaration v = s.isVarDeclaration();
|
|
553 assert(v && v.storage_class & STC.STCfield);
|
|
554 if (v.storage_class & STC.STCref)
|
|
555 continue;
|
|
556 Type tv = v.type.toBasetype();
|
|
557 size_t dim = 1;
|
|
558 while (tv.ty == TY.Tsarray)
|
|
559 { TypeSArray ta = cast(TypeSArray)tv;
|
|
560 dim *= (cast(TypeSArray)tv).dim.toInteger();
|
|
561 tv = tv.nextOf().toBasetype();
|
|
562 }
|
|
563 if (tv.ty == TY.Tstruct)
|
|
564 { TypeStruct ts = cast(TypeStruct)tv;
|
|
565 StructDeclaration sd = ts.sym;
|
|
566 if (sd.postblit)
|
|
567 { Expression ex;
|
|
568
|
|
569 // this.v
|
|
570 ex = new ThisExp(Loc(0));
|
|
571 ex = new DotVarExp(Loc(0), ex, v, 0);
|
|
572
|
|
573 if (dim == 1)
|
|
574 { // this.v.postblit()
|
|
575 ex = new DotVarExp(Loc(0), ex, sd.postblit, 0);
|
|
576 ex = new CallExp(Loc(0), ex);
|
|
577 }
|
|
578 else
|
|
579 {
|
|
580 // Typeinfo.postblit(cast(void*)&this.v);
|
|
581 Expression ea = new AddrExp(Loc(0), ex);
|
|
582 ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo());
|
|
583
|
|
584 Expression et = v.type.getTypeInfo(sc);
|
|
585 et = new DotIdExp(Loc(0), et, Id.postblit);
|
|
586
|
|
587 ex = new CallExp(Loc(0), et, ea);
|
|
588 }
|
|
589 e = Expression.combine(e, ex); // combine in forward order
|
|
590 }
|
|
591 }
|
|
592 }
|
|
593
|
|
594 /* Build our own "postblit" which executes e
|
|
595 */
|
|
596 if (e)
|
|
597 { //printf("Building __fieldPostBlit()\n");
|
|
598 PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldPostBlit"));
|
|
599 dd.fbody = new ExpStatement(Loc(0), e);
|
|
600 postblits.shift(cast(void*)dd);
|
|
601 members.push(cast(void*)dd);
|
|
602 dd.semantic(sc);
|
|
603 }
|
|
604
|
|
605 switch (postblits.dim)
|
|
606 {
|
|
607 case 0:
|
|
608 return null;
|
|
609
|
|
610 case 1:
|
|
611 return cast(FuncDeclaration)postblits.data[0];
|
|
612
|
|
613 default:
|
|
614 e = null;
|
|
615 for (size_t i = 0; i < postblits.dim; i++)
|
|
616 { FuncDeclaration fd = cast(FuncDeclaration)postblits.data[i];
|
|
617 Expression ex = new ThisExp(Loc(0));
|
|
618 ex = new DotVarExp(Loc(0), ex, fd, 0);
|
|
619 ex = new CallExp(Loc(0), ex);
|
|
620 e = Expression.combine(e, ex);
|
|
621 }
|
|
622 PostBlitDeclaration dd = new PostBlitDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrPostBlit"));
|
|
623 dd.fbody = new ExpStatement(Loc(0), e);
|
|
624 members.push(cast(void*)dd);
|
|
625 dd.semantic(sc);
|
|
626 return dd;
|
|
627 }
|
|
628 }
|
|
629 }
|
|
630
|
|
631 /*******************************************
|
|
632 * Build copy constructor for struct.
|
|
633 * Copy constructors are compiler generated only, and are only
|
|
634 * callable from the compiler. They are not user accessible.
|
|
635 * A copy constructor is:
|
|
636 * void cpctpr(ref S s)
|
|
637 * {
|
|
638 * *this = s;
|
|
639 * this.postBlit();
|
|
640 * }
|
|
641 * This is done so:
|
|
642 * - postBlit() never sees uninitialized data
|
|
643 * - memcpy can be much more efficient than memberwise copy
|
|
644 * - no fields are overlooked
|
|
645 */
|
|
646 FuncDeclaration buildCpCtor(Scope sc)
|
|
647 {
|
|
648 //printf("StructDeclaration.buildCpCtor() %s\n", toChars());
|
|
649 FuncDeclaration fcp = null;
|
|
650
|
|
651 /* Copy constructor is only necessary if there is a postblit function,
|
|
652 * otherwise the code generator will just do a bit copy.
|
|
653 */
|
|
654 if (postblit)
|
|
655 {
|
|
656 //printf("generating cpctor\n");
|
|
657
|
|
658 Argument param = new Argument(STC.STCref, type, Id.p, null);
|
|
659 Arguments fparams = new Arguments;
|
|
660 fparams.push(cast(void*)param);
|
|
661 Type ftype = new TypeFunction(fparams, Type.tvoid, false, LINK.LINKd);
|
|
662
|
|
663 fcp = new FuncDeclaration(Loc(0), Loc(0), Id.cpctor, STC.STCundefined, ftype);
|
|
664
|
|
665 // Build *this = p;
|
|
666 Expression e = new ThisExp(Loc(0));
|
|
667 version (STRUCTTHISREF) {
|
|
668 } else {
|
|
669 e = new PtrExp(Loc(0), e);
|
|
670 }
|
|
671 AssignExp ea = new AssignExp(Loc(0), e, new IdentifierExp(Loc(0), Id.p));
|
|
672 ea.op = TOK.TOKblit;
|
|
673 Statement s = new ExpStatement(Loc(0), ea);
|
|
674
|
|
675 // Build postBlit();
|
|
676 e = new VarExp(Loc(0), postblit, 0);
|
|
677 e = new CallExp(Loc(0), e);
|
|
678
|
|
679 s = new CompoundStatement(Loc(0), s, new ExpStatement(Loc(0), e));
|
|
680 fcp.fbody = s;
|
|
681
|
|
682 members.push(cast(void*)fcp);
|
|
683
|
|
684 sc = sc.push();
|
|
685 sc.stc = STC.STCundefined;
|
|
686 sc.linkage = LINK.LINKd;
|
|
687
|
|
688 fcp.semantic(sc);
|
|
689
|
|
690 sc.pop();
|
|
691 }
|
|
692
|
|
693 return fcp;
|
|
694 }
|
|
695
|
|
696 void toDocBuffer(OutBuffer buf)
|
|
697 {
|
|
698 assert(false);
|
|
699 }
|
|
700
|
|
701 PROT getAccess(Dsymbol smember) // determine access to smember
|
|
702 {
|
|
703 assert(false);
|
|
704 }
|
|
705
|
|
706 void toObjFile(int multiobj) // compile to .obj file
|
|
707 {
|
|
708 //printf("StructDeclaration.toObjFile('%s')\n", toChars());
|
|
709
|
|
710 if (multiobj)
|
|
711 {
|
|
712 obj_append(this);
|
|
713 return;
|
|
714 }
|
|
715
|
|
716 // Anonymous structs/unions only exist as part of others,
|
|
717 // do not output forward referenced structs's
|
|
718 if (!isAnonymous() && members)
|
|
719 {
|
|
720 if (global.params.symdebug) {
|
|
721 toDebug();
|
|
722 }
|
|
723
|
|
724 type.getTypeInfo(null); // generate TypeInfo
|
|
725
|
|
726 if (true)
|
|
727 {
|
|
728 // Generate static initializer
|
|
729 toInitializer();
|
|
730
|
|
731 static if (false) {
|
|
732 sinit.Sclass = SC.SCcomdat;
|
|
733 } else {
|
|
734 if (inTemplateInstance())
|
|
735 {
|
|
736 sinit.Sclass = SC.SCcomdat;
|
|
737 }
|
|
738 else
|
|
739 {
|
|
740 sinit.Sclass = SC.SCglobal;
|
|
741 }
|
|
742 }
|
|
743 sinit.Sfl = FL.FLdata;
|
|
744
|
|
745 toDt(&sinit.Sdt);
|
|
746
|
|
747 version (OMFOBJ) {
|
|
748 /* For OMF, common blocks aren't pulled in from the library.
|
|
749 */
|
|
750 /* ELF comdef's generate multiple
|
|
751 * definition errors for them from the gnu linker.
|
|
752 * Need to figure out how to generate proper comdef's for ELF.
|
|
753 */
|
|
754 // See if we can convert a comdat to a comdef,
|
|
755 // which saves on exe file space.
|
|
756 if (sinit.Sclass == SCcomdat &&
|
|
757 sinit.Sdt &&
|
|
758 sinit.Sdt.dt == DT.DT_azeros &&
|
|
759 sinit.Sdt.DTnext == null &&
|
|
760 !global.params.multiobj)
|
|
761 {
|
|
762 sinit.Sclass = SC.SCglobal;
|
|
763 sinit.Sdt.dt = DT.DT_common;
|
|
764 }
|
|
765 }
|
|
766
|
|
767 version (ELFOBJ) {
|
|
768 sinit.Sseg = Segment.CDATA;
|
|
769 }
|
|
770 version (MACHOBJ) {
|
|
771 sinit.Sseg = Segment.DATA;
|
|
772 }
|
|
773 outdata(sinit);
|
|
774 }
|
|
775
|
|
776 // Put out the members
|
|
777 for (uint i = 0; i < members.dim; i++)
|
|
778 {
|
|
779 Dsymbol member = cast(Dsymbol)members.data[i];
|
|
780 member.toObjFile(0);
|
|
781 }
|
|
782 }
|
|
783 }
|
|
784
|
|
785 void toDt(dt_t** pdt)
|
|
786 {
|
|
787 uint offset;
|
|
788 uint i;
|
|
789 dt_t* dt;
|
|
790
|
|
791 //printf("StructDeclaration.toDt(), this='%s'\n", toChars());
|
|
792 offset = 0;
|
|
793
|
|
794 // Note equivalence of this loop to class's
|
|
795 for (i = 0; i < fields.dim; i++)
|
|
796 {
|
|
797 VarDeclaration v = cast(VarDeclaration)fields.data[i];
|
|
798 //printf("\tfield '%s' voffset %d, offset = %d\n", v.toChars(), v.offset, offset);
|
|
799 dt = null;
|
|
800 int sz;
|
|
801
|
|
802 if (v.storage_class & STC.STCref)
|
|
803 {
|
|
804 sz = PTRSIZE;
|
|
805 if (v.offset >= offset)
|
|
806 dtnzeros(&dt, sz);
|
|
807 }
|
|
808 else
|
|
809 {
|
|
810 sz = cast(uint)v.type.size();
|
|
811 Initializer init = v.init;
|
|
812 if (init)
|
|
813 {
|
|
814 //printf("\t\thas initializer %s\n", init.toChars());
|
|
815 ExpInitializer ei = init.isExpInitializer();
|
|
816 Type tb = v.type.toBasetype();
|
|
817 if (ei && tb.ty == TY.Tsarray)
|
|
818 (cast(TypeSArray)tb).toDtElem(&dt, ei.exp);
|
|
819 else
|
|
820 dt = init.toDt();
|
|
821 }
|
|
822 else if (v.offset >= offset)
|
|
823 v.type.toDt(&dt);
|
|
824 }
|
|
825 if (dt)
|
|
826 {
|
|
827 if (v.offset < offset)
|
|
828 error("overlapping initialization for struct %s.%s", toChars(), v.toChars());
|
|
829 else
|
|
830 {
|
|
831 if (offset < v.offset)
|
|
832 dtnzeros(pdt, v.offset - offset);
|
|
833 dtcat(pdt, dt);
|
|
834 offset = v.offset + sz;
|
|
835 }
|
|
836 }
|
|
837 }
|
|
838
|
|
839 if (offset < structsize)
|
|
840 dtnzeros(pdt, structsize - offset);
|
|
841
|
|
842 dt_optimize(*pdt);
|
|
843 }
|
|
844
|
|
845 void toDebug() // to symbolic debug info
|
|
846 {
|
|
847 assert(false);
|
|
848 }
|
|
849
|
|
850 StructDeclaration isStructDeclaration() { return this; }
|
|
851 } |