Mercurial > projects > ddmd
comparison dmd/AggregateDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 5c9b78899f5d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:10317f0c89a5 |
---|---|
1 module dmd.AggregateDeclaration; | |
2 | |
3 import dmd.ScopeDsymbol; | |
4 import dmd.Type; | |
5 import dmd.Id; | |
6 import dmd.ExpStatement; | |
7 import dmd.AddrExp; | |
8 import dmd.CastExp; | |
9 import dmd.TypeSArray; | |
10 import dmd.DotVarExp; | |
11 import dmd.TypeStruct; | |
12 import dmd.StructDeclaration; | |
13 import dmd.Declaration; | |
14 import dmd.TypeClass; | |
15 import dmd.TOK; | |
16 import dmd.ThisExp; | |
17 import dmd.PROT; | |
18 import dmd.Expression; | |
19 import dmd.STC; | |
20 import dmd.DotIdExp; | |
21 import dmd.CallExp; | |
22 import dmd.DtorDeclaration; | |
23 import dmd.Lexer; | |
24 import dmd.TY; | |
25 import dmd.Array; | |
26 import dmd.ArrayTypes; | |
27 import dmd.VarDeclaration; | |
28 import dmd.InvariantDeclaration; | |
29 import dmd.NewDeclaration; | |
30 import dmd.DeleteDeclaration; | |
31 import dmd.CtorDeclaration; | |
32 import dmd.FuncDeclaration; | |
33 import dmd.Identifier; | |
34 import dmd.Loc; | |
35 import dmd.Dsymbol; | |
36 import dmd.Scope; | |
37 import dmd.OutBuffer; | |
38 import dmd.ClassDeclaration; | |
39 import dmd.BaseClass; | |
40 import dmd.Util; | |
41 | |
42 import dmd.backend.Symbol; | |
43 import dmd.backend.Classsym; | |
44 import dmd.backend.Util; | |
45 import dmd.backend.LIST; | |
46 import dmd.backend.SC; | |
47 import dmd.backend.FL; | |
48 import dmd.backend.SFL; | |
49 import dmd.codegen.Util; | |
50 | |
51 /**************************************** | |
52 * Determine if scope sc has package level access to s. | |
53 */ | |
54 | |
55 bool hasPackageAccess(Scope sc, Dsymbol s) | |
56 { | |
57 version (LOG) { | |
58 printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); | |
59 } | |
60 | |
61 for (; s; s = s.parent) | |
62 { | |
63 if (s.isPackage() && !s.isModule()) | |
64 break; | |
65 } | |
66 version (LOG) { | |
67 if (s) | |
68 printf("\tthis is in package '%s'\n", s.toChars()); | |
69 } | |
70 | |
71 if (s && s == sc.module_.parent) | |
72 { | |
73 version (LOG) { | |
74 printf("\ts is in same package as sc\n"); | |
75 } | |
76 return true; | |
77 } | |
78 | |
79 | |
80 version (LOG) { | |
81 printf("\tno package access\n"); | |
82 } | |
83 | |
84 return false; | |
85 } | |
86 | |
87 /******************************************************** | |
88 * Helper function for ClassDeclaration.accessCheck() | |
89 * Returns: | |
90 * 0 no access | |
91 * 1 access | |
92 */ | |
93 | |
94 bool accessCheckX(Dsymbol smember, Dsymbol sfunc, AggregateDeclaration dthis, AggregateDeclaration cdscope) | |
95 { | |
96 assert(dthis); | |
97 | |
98 static if (false) { | |
99 writef("accessCheckX for %s.%s in function %s() in scope %s\n", dthis.toChars(), smember.toChars(), sfunc ? sfunc.toChars() : "null", cdscope ? cdscope.toChars() : "null"); | |
100 } | |
101 if (dthis.hasPrivateAccess(sfunc) || dthis.isFriendOf(cdscope)) | |
102 { | |
103 if (smember.toParent() == dthis) | |
104 return true; | |
105 else | |
106 { | |
107 ClassDeclaration cdthis = dthis.isClassDeclaration(); | |
108 if (cdthis) | |
109 { | |
110 for (int i = 0; i < cdthis.baseclasses.dim; i++) | |
111 { | |
112 BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; | |
113 PROT access = b.base.getAccess(smember); | |
114 | |
115 if (access >= PROT.PROTprotected || accessCheckX(smember, sfunc, b.base, cdscope)) | |
116 return true; | |
117 } | |
118 } | |
119 } | |
120 } | |
121 else | |
122 { | |
123 if (smember.toParent() != dthis) | |
124 { | |
125 ClassDeclaration cdthis = dthis.isClassDeclaration(); | |
126 if (cdthis) | |
127 { | |
128 for (int i = 0; i < cdthis.baseclasses.dim; i++) | |
129 { | |
130 BaseClass b = cast(BaseClass)cdthis.baseclasses.data[i]; | |
131 | |
132 if (accessCheckX(smember, sfunc, b.base, cdscope)) | |
133 return true; | |
134 } | |
135 } | |
136 } | |
137 } | |
138 | |
139 return false; | |
140 } | |
141 | |
142 class AggregateDeclaration : ScopeDsymbol | |
143 { | |
144 Type type; | |
145 uint storage_class; | |
146 PROT protection = PROT.PROTpublic; | |
147 Type handle; // 'this' type | |
148 uint structsize; // size of struct | |
149 uint alignsize; // size of struct for alignment purposes | |
150 uint structalign; // struct member alignment in effect | |
151 int hasUnions; // set if aggregate has overlapping fields | |
152 Array fields; // VarDeclaration fields | |
153 uint sizeok; // set when structsize contains valid data | |
154 // 0: no size | |
155 // 1: size is correct | |
156 // 2: cannot determine size; fwd referenced | |
157 bool isdeprecated; // true if deprecated | |
158 | |
159 bool isnested; // true if is nested | |
160 VarDeclaration vthis; // 'this' parameter if this aggregate is nested | |
161 | |
162 // Special member functions | |
163 InvariantDeclaration inv; // invariant | |
164 NewDeclaration aggNew; // allocator | |
165 DeleteDeclaration aggDelete; // deallocator | |
166 | |
167 version (DMDV2) { | |
168 //CtorDeclaration *ctor; | |
169 Dsymbol ctor; // CtorDeclaration or TemplateDeclaration | |
170 CtorDeclaration defaultCtor; // default constructor | |
171 Dsymbol aliasthis; // forward unresolved lookups to aliasthis | |
172 } | |
173 | |
174 FuncDeclarations dtors; // Array of destructors | |
175 FuncDeclaration dtor; // aggregate destructor | |
176 | |
177 version (IN_GCC) { | |
178 Array methods; // flat list of all methods for debug information | |
179 } | |
180 | |
181 this(Loc loc, Identifier id) | |
182 { | |
183 super(id); | |
184 this.loc = loc; | |
185 | |
186 fields = new Array(); /// | |
187 dtors = new FuncDeclarations(); | |
188 } | |
189 | |
190 void semantic2(Scope sc) | |
191 { | |
192 //printf("AggregateDeclaration.semantic2(%s)\n", toChars()); | |
193 if (scope_ && members) | |
194 { | |
195 error("has forward references"); | |
196 return; | |
197 } | |
198 if (members) | |
199 { | |
200 sc = sc.push(this); | |
201 for (size_t i = 0; i < members.dim; i++) | |
202 { | |
203 Dsymbol s = cast(Dsymbol)members.data[i]; | |
204 s.semantic2(sc); | |
205 } | |
206 sc.pop(); | |
207 } | |
208 } | |
209 | |
210 void semantic3(Scope sc) | |
211 { | |
212 int i; | |
213 | |
214 //printf("AggregateDeclaration.semantic3(%s)\n", toChars()); | |
215 if (members) | |
216 { | |
217 sc = sc.push(this); | |
218 for (i = 0; i < members.dim; i++) | |
219 { | |
220 Dsymbol s = cast(Dsymbol)members.data[i]; | |
221 s.semantic3(sc); | |
222 } | |
223 sc.pop(); | |
224 } | |
225 } | |
226 | |
227 void inlineScan() | |
228 { | |
229 int i; | |
230 | |
231 //printf("AggregateDeclaration.inlineScan(%s)\n", toChars()); | |
232 if (members) | |
233 { | |
234 for (i = 0; i < members.dim; i++) | |
235 { | |
236 Dsymbol s = cast(Dsymbol)members.data[i]; | |
237 //printf("inline scan aggregate symbol '%s'\n", s.toChars()); | |
238 s.inlineScan(); | |
239 } | |
240 } | |
241 } | |
242 | |
243 uint size(Loc loc) | |
244 { | |
245 //printf("AggregateDeclaration.size() = %d\n", structsize); | |
246 if (!members) | |
247 error(loc, "unknown size"); | |
248 | |
249 if (sizeok != 1) | |
250 { | |
251 error(loc, "no size yet for forward reference"); | |
252 //*(char*)0=0; | |
253 } | |
254 | |
255 return structsize; | |
256 } | |
257 | |
258 /**************************** | |
259 * Do byte or word alignment as necessary. | |
260 * Align sizes of 0, as we may not know array sizes yet. | |
261 */ | |
262 static void alignmember(uint salign, uint size, uint* poffset) | |
263 { | |
264 //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); | |
265 if (salign > 1) | |
266 { | |
267 assert(size != 3); | |
268 int sa = size; | |
269 if (sa == 0 || salign < sa) | |
270 sa = salign; | |
271 *poffset = (*poffset + sa - 1) & ~(sa - 1); | |
272 } | |
273 //printf("result = %d\n",offset); | |
274 } | |
275 | |
276 Type getType() | |
277 { | |
278 return type; | |
279 } | |
280 | |
281 void addField(Scope sc, VarDeclaration v) | |
282 { | |
283 uint memsize; // size of member | |
284 uint memalignsize; // size of member for alignment purposes | |
285 uint xalign; // alignment boundaries | |
286 | |
287 //printf("AggregateDeclaration.addField('%s') %s\n", v.toChars(), toChars()); | |
288 assert(!(v.storage_class & (STC.STCstatic | STC.STCextern | STC.STCparameter | STC.STCtls))); | |
289 | |
290 // Check for forward referenced types which will fail the size() call | |
291 Type t = v.type.toBasetype(); | |
292 if (v.storage_class & STC.STCref) | |
293 { // References are the size of a pointer | |
294 t = Type.tvoidptr; | |
295 } | |
296 if (t.ty == TY.Tstruct /*&& isStructDeclaration()*/) | |
297 { TypeStruct ts = cast(TypeStruct)t; | |
298 version (DMDV2) { | |
299 if (ts.sym == this) | |
300 { | |
301 error("cannot have field %s with same struct type", v.toChars()); | |
302 } | |
303 } | |
304 | |
305 if (ts.sym.sizeok != 1) | |
306 { | |
307 sizeok = 2; // cannot finish; flag as forward referenced | |
308 return; | |
309 } | |
310 } | |
311 if (t.ty == TY.Tident) | |
312 { | |
313 sizeok = 2; // cannot finish; flag as forward referenced | |
314 return; | |
315 } | |
316 | |
317 memsize = cast(uint)t.size(loc); /// | |
318 memalignsize = t.alignsize(); | |
319 xalign = t.memalign(sc.structalign); | |
320 alignmember(xalign, memalignsize, &sc.offset); | |
321 v.offset = sc.offset; | |
322 sc.offset += memsize; | |
323 if (sc.offset > structsize) | |
324 structsize = sc.offset; | |
325 if (sc.structalign < memalignsize) | |
326 memalignsize = sc.structalign; | |
327 if (alignsize < memalignsize) | |
328 alignsize = memalignsize; | |
329 //printf("\talignsize = %d\n", alignsize); | |
330 | |
331 v.storage_class |= STC.STCfield; | |
332 //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v.toChars(), toChars(), v.offset, memsize); | |
333 fields.push(cast(void*)v); | |
334 } | |
335 | |
336 bool isDeprecated() // is aggregate deprecated? | |
337 { | |
338 return isdeprecated; | |
339 } | |
340 | |
341 /***************************************** | |
342 * Create inclusive destructor for struct/class by aggregating | |
343 * all the destructors in dtors[] with the destructors for | |
344 * all the members. | |
345 * Note the close similarity with StructDeclaration.buildPostBlit(), | |
346 * and the ordering changes (runs backward instead of forwards). | |
347 */ | |
348 FuncDeclaration buildDtor(Scope sc) | |
349 { | |
350 //printf("AggregateDeclaration.buildDtor() %s\n", toChars()); | |
351 Expression e = null; | |
352 | |
353 version (DMDV2) { | |
354 for (size_t i = 0; i < fields.dim; i++) | |
355 { | |
356 Dsymbol s = cast(Dsymbol)fields.data[i]; | |
357 VarDeclaration v = s.isVarDeclaration(); | |
358 assert(v && v.storage_class & STC.STCfield); | |
359 if (v.storage_class & STC.STCref) | |
360 continue; | |
361 Type tv = v.type.toBasetype(); | |
362 size_t dim = 1; | |
363 while (tv.ty == TY.Tsarray) | |
364 { TypeSArray ta = cast(TypeSArray)tv; | |
365 dim *= (cast(TypeSArray)tv).dim.toInteger(); | |
366 tv = tv.nextOf().toBasetype(); | |
367 } | |
368 if (tv.ty == TY.Tstruct) | |
369 { TypeStruct ts = cast(TypeStruct)tv; | |
370 StructDeclaration sd = ts.sym; | |
371 if (sd.dtor) | |
372 { | |
373 Expression ex; | |
374 | |
375 // this.v | |
376 ex = new ThisExp(Loc(0)); | |
377 ex = new DotVarExp(Loc(0), ex, v, 0); | |
378 | |
379 if (dim == 1) | |
380 { | |
381 // this.v.dtor() | |
382 ex = new DotVarExp(Loc(0), ex, sd.dtor, 0); | |
383 ex = new CallExp(Loc(0), ex); | |
384 } | |
385 else | |
386 { | |
387 // Typeinfo.destroy(cast(void*)&this.v); | |
388 Expression ea = new AddrExp(Loc(0), ex); | |
389 ea = new CastExp(Loc(0), ea, Type.tvoid.pointerTo()); | |
390 | |
391 Expression et = v.type.getTypeInfo(sc); | |
392 et = new DotIdExp(Loc(0), et, Id.destroy); | |
393 | |
394 ex = new CallExp(Loc(0), et, ea); | |
395 } | |
396 e = Expression.combine(ex, e); // combine in reverse order | |
397 } | |
398 } | |
399 } | |
400 | |
401 /* Build our own "destructor" which executes e | |
402 */ | |
403 if (e) | |
404 { | |
405 //printf("Building __fieldDtor()\n"); | |
406 DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__fieldDtor")); | |
407 dd.fbody = new ExpStatement(Loc(0), e); | |
408 dtors.shift(cast(void*)dd); | |
409 members.push(cast(void*)dd); | |
410 dd.semantic(sc); | |
411 } | |
412 } | |
413 | |
414 switch (dtors.dim) | |
415 { | |
416 case 0: | |
417 return null; | |
418 | |
419 case 1: | |
420 return cast(FuncDeclaration)dtors.data[0]; | |
421 | |
422 default: | |
423 e = null; | |
424 for (size_t i = 0; i < dtors.dim; i++) | |
425 { | |
426 FuncDeclaration fd = cast(FuncDeclaration)dtors.data[i]; | |
427 Expression ex = new ThisExp(Loc(0)); | |
428 ex = new DotVarExp(Loc(0), ex, fd, 0); | |
429 ex = new CallExp(Loc(0), ex); | |
430 e = Expression.combine(ex, e); | |
431 } | |
432 DtorDeclaration dd = new DtorDeclaration(Loc(0), Loc(0), Lexer.idPool("__aggrDtor")); | |
433 dd.fbody = new ExpStatement(Loc(0), e); | |
434 members.push(cast(void*)dd); | |
435 dd.semantic(sc); | |
436 return dd; | |
437 } | |
438 } | |
439 | |
440 /**************************************** | |
441 * Returns true if there's an extra member which is the 'this' | |
442 * pointer to the enclosing context (enclosing aggregate or function) | |
443 */ | |
444 bool isNested() | |
445 { | |
446 return isnested; | |
447 } | |
448 | |
449 void emitComment(Scope sc) | |
450 { | |
451 assert(false); | |
452 } | |
453 | |
454 void toDocBuffer(OutBuffer buf) | |
455 { | |
456 assert(false); | |
457 } | |
458 | |
459 // For access checking | |
460 PROT getAccess(Dsymbol smember) // determine access to smember | |
461 { | |
462 assert(false); | |
463 } | |
464 | |
465 /**************************************** | |
466 * Determine if this is the same or friend of cd. | |
467 */ | |
468 bool isFriendOf(AggregateDeclaration cd) | |
469 { | |
470 version (LOG) { | |
471 printf("AggregateDeclaration.isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd.toChars() : "null"); | |
472 } | |
473 if (this is cd) | |
474 return true; | |
475 | |
476 // Friends if both are in the same module | |
477 //if (toParent() == cd.toParent()) | |
478 if (cd && getModule() == cd.getModule()) | |
479 { | |
480 version (LOG) { | |
481 printf("\tin same module\n"); | |
482 } | |
483 return true; | |
484 } | |
485 | |
486 version (LOG) { | |
487 printf("\tnot friend\n"); | |
488 } | |
489 return false; | |
490 } | |
491 | |
492 /********************************** | |
493 * Determine if smember has access to private members of this declaration. | |
494 */ | |
495 bool hasPrivateAccess(Dsymbol smember) // does smember have private access to members of this class? | |
496 { | |
497 if (smember) | |
498 { | |
499 AggregateDeclaration cd = null; | |
500 Dsymbol smemberparent = smember.toParent(); | |
501 if (smemberparent) | |
502 cd = smemberparent.isAggregateDeclaration(); | |
503 | |
504 version (LOG) { | |
505 printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", toChars(), smember.toChars()); | |
506 } | |
507 | |
508 if (this == cd) // smember is a member of this class | |
509 { | |
510 version (LOG) { | |
511 printf("\tyes 1\n"); | |
512 } | |
513 return true; // so we get private access | |
514 } | |
515 | |
516 // If both are members of the same module, grant access | |
517 while (true) | |
518 { | |
519 Dsymbol sp = smember.toParent(); | |
520 if (sp.isFuncDeclaration() && smember.isFuncDeclaration()) | |
521 smember = sp; | |
522 else | |
523 break; | |
524 } | |
525 if (!cd && toParent() == smember.toParent()) | |
526 { | |
527 version (LOG) { | |
528 printf("\tyes 2\n"); | |
529 } | |
530 return true; | |
531 } | |
532 if (!cd && getModule() == smember.getModule()) | |
533 { | |
534 version (LOG) { | |
535 printf("\tyes 3\n"); | |
536 } | |
537 return true; | |
538 } | |
539 } | |
540 version (LOG) { | |
541 printf("\tno\n"); | |
542 } | |
543 return false; | |
544 } | |
545 | |
546 /******************************* | |
547 * Do access check for member of this class, this class being the | |
548 * type of the 'this' pointer used to access smember. | |
549 */ | |
550 void accessCheck(Loc loc, Scope sc, Dsymbol smember) | |
551 { | |
552 bool result; | |
553 | |
554 FuncDeclaration f = sc.func; | |
555 AggregateDeclaration cdscope = sc.getStructClassScope(); | |
556 PROT access; | |
557 | |
558 version (LOG) { | |
559 printf("AggregateDeclaration.accessCheck() for %s.%s in function %s() in scope %s\n", toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null); | |
560 } | |
561 | |
562 Dsymbol smemberparent = smember.toParent(); | |
563 if (!smemberparent || !smemberparent.isAggregateDeclaration()) | |
564 { | |
565 version (LOG) { | |
566 printf("not an aggregate member\n"); | |
567 } | |
568 return; // then it is accessible | |
569 } | |
570 | |
571 // BUG: should enable this check | |
572 //assert(smember.parent.isBaseOf(this, null)); | |
573 | |
574 if (smemberparent == this) | |
575 { | |
576 PROT access2 = smember.prot(); | |
577 | |
578 result = access2 >= PROT.PROTpublic || | |
579 hasPrivateAccess(f) || | |
580 isFriendOf(cdscope) || | |
581 (access2 == PROT.PROTpackage && hasPackageAccess(sc, this)); | |
582 | |
583 version (LOG) { | |
584 printf("result1 = %d\n", result); | |
585 } | |
586 } | |
587 else if ((access = this.getAccess(smember)) >= PROT.PROTpublic) | |
588 { | |
589 result = true; | |
590 version (LOG) { | |
591 printf("result2 = %d\n", result); | |
592 } | |
593 } | |
594 else if (access == PROT.PROTpackage && hasPackageAccess(sc, this)) | |
595 { | |
596 result = true; | |
597 version (LOG) { | |
598 printf("result3 = %d\n", result); | |
599 } | |
600 } | |
601 else | |
602 { | |
603 result = accessCheckX(smember, f, this, cdscope); | |
604 version (LOG) { | |
605 printf("result4 = %d\n", result); | |
606 } | |
607 } | |
608 if (!result) | |
609 { | |
610 error(loc, "member %s is not accessible", smember.toChars()); | |
611 halt(); | |
612 } | |
613 } | |
614 | |
615 PROT prot() | |
616 { | |
617 assert(false); | |
618 } | |
619 | |
620 // Back end | |
621 Symbol* stag; // tag symbol for debug data | |
622 Symbol* sinit; | |
623 | |
624 Symbol* toInitializer() | |
625 { | |
626 Symbol* s; | |
627 Classsym* stag; | |
628 | |
629 if (!sinit) | |
630 { | |
631 stag = fake_classsym(Id.ClassInfo); | |
632 s = toSymbolX("__init", SC.SCextern, stag.Stype, "Z"); | |
633 s.Sfl = FL.FLextern; | |
634 s.Sflags |= SFL.SFLnodebug; | |
635 slist_add(s); | |
636 sinit = s; | |
637 } | |
638 | |
639 return sinit; | |
640 } | |
641 | |
642 AggregateDeclaration isAggregateDeclaration() { return this; } | |
643 } |