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