1 /**
2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
3 *
4 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d)
8 * Documentation: https://dlang.org/phobos/dmd_dsymbol.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d
10 */
11
12 module dmd.dsymbol;
13
14 import core.stdc.stdarg;
15 import core.stdc.stdio;
16 import core.stdc.string;
17 import core.stdc.stdlib;
18
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arraytypes;
22 import dmd.attrib;
23 import dmd.astenums;
24 import dmd.ast_node;
25 import dmd.gluelayer;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dmodule;
31 import dmd.dversion;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbolsem;
35 import dmd.dtemplate;
36 import dmd.errors;
37 import dmd.expression;
38 import dmd.expressionsem;
39 import dmd.func;
40 import dmd.globals;
41 import dmd.id;
42 import dmd.identifier;
43 import dmd.init;
44 import dmd.lexer;
45 import dmd.mtype;
46 import dmd.nspace;
47 import dmd.opover;
48 import dmd.root.aav;
49 import dmd.root.rmem;
50 import dmd.root.rootobject;
51 import dmd.root.speller;
52 import dmd.root.string;
53 import dmd.statement;
54 import dmd.staticassert;
55 import dmd.tokens;
56 import dmd.visitor;
57
58 /***************************************
59 * Calls dg(Dsymbol *sym) for each Dsymbol.
60 * If dg returns !=0, stops and returns that value else returns 0.
61 * Params:
62 * symbols = Dsymbols
63 * dg = delegate to call for each Dsymbol
64 * Returns:
65 * last value returned by dg()
66 *
67 * See_Also: $(REF each, dmd, root, array)
68 */
foreachDsymbol(Dsymbols * symbols,scope int delegate (Dsymbol)dg)69 int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
70 {
71 assert(dg);
72 if (symbols)
73 {
74 /* Do not use foreach, as the size of the array may expand during iteration
75 */
76 for (size_t i = 0; i < symbols.dim; ++i)
77 {
78 Dsymbol s = (*symbols)[i];
79 const result = dg(s);
80 if (result)
81 return result;
82 }
83 }
84 return 0;
85 }
86
87 /***************************************
88 * Calls dg(Dsymbol *sym) for each Dsymbol.
89 * Params:
90 * symbols = Dsymbols
91 * dg = delegate to call for each Dsymbol
92 *
93 * See_Also: $(REF each, dmd, root, array)
94 */
foreachDsymbol(Dsymbols * symbols,scope void delegate (Dsymbol)dg)95 void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
96 {
97 assert(dg);
98 if (symbols)
99 {
100 /* Do not use foreach, as the size of the array may expand during iteration
101 */
102 for (size_t i = 0; i < symbols.dim; ++i)
103 {
104 Dsymbol s = (*symbols)[i];
105 dg(s);
106 }
107 }
108 }
109
110
111 struct Ungag
112 {
113 uint oldgag;
114
thisUngag115 extern (D) this(uint old) nothrow
116 {
117 this.oldgag = old;
118 }
119
~thisUngag120 extern (C++) ~this() nothrow
121 {
122 global.gag = oldgag;
123 }
124 }
125
126 struct Visibility
127 {
128 ///
129 enum Kind : ubyte
130 {
131 undefined,
132 none, // no access
133 private_,
134 package_,
135 protected_,
136 public_,
137 export_,
138 }
139
140 Kind kind;
141 Package pkg;
142
143 extern (D):
144
145 this(Visibility.Kind kind) pure nothrow @nogc @safe
146 {
147 this.kind = kind;
148 }
149
150 /**
151 * Checks if `this` is less or more visible than `other`
152 *
153 * Params:
154 * other = Visibility to compare `this` to.
155 *
156 * Returns:
157 * A value `< 0` if `this` is less visible than `other`,
158 * a value `> 0` if `this` is more visible than `other`,
159 * and `0` if they are at the same level.
160 * Note that `package` visibility with different packages
161 * will also return `0`.
162 */
opCmp(const Visibility other)163 int opCmp(const Visibility other) const pure nothrow @nogc @safe
164 {
165 return this.kind - other.kind;
166 }
167
168 ///
169 unittest
170 {
171 assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_));
172 assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_));
173 assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_));
174 }
175
176 /**
177 * Checks if `this` is absolutely identical visibility attribute to `other`
178 */
opEquals(ref const Visibility other)179 bool opEquals(ref const Visibility other) const
180 {
181 if (this.kind == other.kind)
182 {
183 if (this.kind == Visibility.Kind.package_)
184 return this.pkg == other.pkg;
185 return true;
186 }
187 return false;
188 }
189 }
190
191 enum PASS : ubyte
192 {
193 initial, // initial state
194 semantic, // semantic() started
195 semanticdone, // semantic() done
196 semantic2, // semantic2() started
197 semantic2done, // semantic2() done
198 semantic3, // semantic3() started
199 semantic3done, // semantic3() done
200 inline, // inline started
201 inlinedone, // inline done
202 obj, // toObjFile() run
203 }
204
205 // Search options
206 enum : int
207 {
208 IgnoreNone = 0x00, // default
209 IgnorePrivateImports = 0x01, // don't search private imports
210 IgnoreErrors = 0x02, // don't give error messages
211 IgnoreAmbiguous = 0x04, // return NULL if ambiguous
212 SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
213 SearchImportsOnly = 0x10, // only look in imports
214 SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
215 // meaning don't search imports in that scope,
216 // because qualified module searches search
217 // their imports
218 IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
219 TagNameSpace = 0x100, // search ImportC tag symbol table
220 }
221
222 /***********************************************************
223 * Struct/Class/Union field state.
224 * Used for transitory information when setting field offsets, such
225 * as bit fields.
226 */
227 struct FieldState
228 {
229 uint offset; /// byte offset for next field
230
231 uint fieldOffset; /// byte offset for the start of the bit field
232 uint fieldSize; /// byte size of field
233 uint fieldAlign; /// byte alignment of field
234 uint bitOffset; /// bit offset for field
235
236 bool inFlight; /// bit field is in flight
237 }
238
239 /***********************************************************
240 */
241 extern (C++) class Dsymbol : ASTNode
242 {
243 Identifier ident;
244 Dsymbol parent;
245 /// C++ namespace this symbol belongs to
246 CPPNamespaceDeclaration cppnamespace;
247 Symbol* csym; // symbol for code generator
248 const Loc loc; // where defined
249 Scope* _scope; // !=null means context to use for semantic()
250 const(char)* prettystring; // cached value of toPrettyChars()
251 bool errors; // this symbol failed to pass semantic()
252 PASS semanticRun = PASS.initial;
253 ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
254
255 DeprecatedDeclaration depdecl; // customized deprecation message
256 UserAttributeDeclaration userAttribDecl; // user defined attributes
257
this()258 final extern (D) this() nothrow
259 {
260 //printf("Dsymbol::Dsymbol(%p)\n", this);
261 loc = Loc(null, 0, 0);
262 }
263
this(Identifier ident)264 final extern (D) this(Identifier ident) nothrow
265 {
266 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
267 this.loc = Loc(null, 0, 0);
268 this.ident = ident;
269 }
270
this(const ref Loc loc,Identifier ident)271 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
272 {
273 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
274 this.loc = loc;
275 this.ident = ident;
276 }
277
create(Identifier ident)278 static Dsymbol create(Identifier ident) nothrow
279 {
280 return new Dsymbol(ident);
281 }
282
toChars()283 override const(char)* toChars() const
284 {
285 return ident ? ident.toChars() : "__anonymous";
286 }
287
288 // helper to print fully qualified (template) arguments
toPrettyCharsHelper()289 const(char)* toPrettyCharsHelper()
290 {
291 return toChars();
292 }
293
getLoc()294 final const(Loc) getLoc()
295 {
296 if (!loc.isValid()) // avoid bug 5861.
297 if (const m = getModule())
298 return Loc(m.srcfile.toChars(), 0, 0);
299 return loc;
300 }
301
locToChars()302 final const(char)* locToChars()
303 {
304 return getLoc().toChars();
305 }
306
equals(const RootObject o)307 override bool equals(const RootObject o) const
308 {
309 if (this == o)
310 return true;
311 if (o.dyncast() != DYNCAST.dsymbol)
312 return false;
313 auto s = cast(Dsymbol)o;
314 // Overload sets don't have an ident
315 // Function-local declarations may have identical names
316 // if they are declared in different scopes
317 if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum)
318 return true;
319 return false;
320 }
321
isAnonymous()322 final bool isAnonymous() const
323 {
324 return ident is null || ident.isAnonymous;
325 }
326
prettyFormatHelper()327 extern(D) private const(char)[] prettyFormatHelper()
328 {
329 const cstr = toPrettyChars();
330 return '`' ~ cstr.toDString() ~ "`\0";
331 }
332
333 static if (__VERSION__ < 2092)
334 {
error(const ref Loc loc,const (char)* format,...)335 final void error(const ref Loc loc, const(char)* format, ...)
336 {
337 va_list ap;
338 va_start(ap, format);
339 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
340 va_end(ap);
341 }
342
error(const (char)* format,...)343 final void error(const(char)* format, ...)
344 {
345 va_list ap;
346 va_start(ap, format);
347 const loc = getLoc();
348 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
349 va_end(ap);
350 }
351
deprecation(const ref Loc loc,const (char)* format,...)352 final void deprecation(const ref Loc loc, const(char)* format, ...)
353 {
354 va_list ap;
355 va_start(ap, format);
356 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
357 va_end(ap);
358 }
359
deprecation(const (char)* format,...)360 final void deprecation(const(char)* format, ...)
361 {
362 va_list ap;
363 va_start(ap, format);
364 const loc = getLoc();
365 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
366 va_end(ap);
367 }
368 }
369 else
370 {
pragma(printf)371 pragma(printf) final void error(const ref Loc loc, const(char)* format, ...)
372 {
373 va_list ap;
374 va_start(ap, format);
375 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
376 va_end(ap);
377 }
378
pragma(printf)379 pragma(printf) final void error(const(char)* format, ...)
380 {
381 va_list ap;
382 va_start(ap, format);
383 const loc = getLoc();
384 .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
385 va_end(ap);
386 }
387
pragma(printf)388 pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...)
389 {
390 va_list ap;
391 va_start(ap, format);
392 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
393 va_end(ap);
394 }
395
pragma(printf)396 pragma(printf) final void deprecation(const(char)* format, ...)
397 {
398 va_list ap;
399 va_start(ap, format);
400 const loc = getLoc();
401 .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
402 va_end(ap);
403 }
404 }
405
checkDeprecated(const ref Loc loc,Scope * sc)406 final bool checkDeprecated(const ref Loc loc, Scope* sc)
407 {
408 if (global.params.useDeprecated == DiagnosticReporting.off)
409 return false;
410 if (!this.isDeprecated())
411 return false;
412 // Don't complain if we're inside a deprecated symbol's scope
413 if (sc.isDeprecated())
414 return false;
415 // Don't complain if we're inside a template constraint
416 // https://issues.dlang.org/show_bug.cgi?id=21831
417 if (sc.flags & SCOPE.constraint)
418 return false;
419
420 const(char)* message = null;
421 for (Dsymbol p = this; p; p = p.parent)
422 {
423 message = p.depdecl ? p.depdecl.getMessage() : null;
424 if (message)
425 break;
426 }
427 if (message)
428 deprecation(loc, "is deprecated - %s", message);
429 else
430 deprecation(loc, "is deprecated");
431
432 if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
433 ti.printInstantiationTrace(Classification.deprecation);
434 else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
435 ti.printInstantiationTrace(Classification.deprecation);
436
437 return true;
438 }
439
440 /**********************************
441 * Determine which Module a Dsymbol is in.
442 */
getModule()443 final Module getModule()
444 {
445 //printf("Dsymbol::getModule()\n");
446 if (TemplateInstance ti = isInstantiated())
447 return ti.tempdecl.getModule();
448 Dsymbol s = this;
449 while (s)
450 {
451 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
452 Module m = s.isModule();
453 if (m)
454 return m;
455 s = s.parent;
456 }
457 return null;
458 }
459
460 /**************************************
461 * Does this Dsymbol come from a C file?
462 * Returns:
463 * true if it does
464 */
isCsymbol()465 final bool isCsymbol()
466 {
467 if (Module m = getModule())
468 return m.filetype == FileType.c;
469 return false;
470 }
471
472 /**********************************
473 * Determine which Module a Dsymbol is in, as far as access rights go.
474 */
getAccessModule()475 final Module getAccessModule()
476 {
477 //printf("Dsymbol::getAccessModule()\n");
478 if (TemplateInstance ti = isInstantiated())
479 return ti.tempdecl.getAccessModule();
480 Dsymbol s = this;
481 while (s)
482 {
483 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
484 Module m = s.isModule();
485 if (m)
486 return m;
487 TemplateInstance ti = s.isTemplateInstance();
488 if (ti && ti.enclosing)
489 {
490 /* Because of local template instantiation, the parent isn't where the access
491 * rights come from - it's the template declaration
492 */
493 s = ti.tempdecl;
494 }
495 else
496 s = s.parent;
497 }
498 return null;
499 }
500
501 /**
502 * `pastMixin` returns the enclosing symbol if this is a template mixin.
503 *
504 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
505 * are mangleOnly.
506 *
507 * See also `parent`, `toParent` and `toParent2`.
508 */
inout(Dsymbol)509 final inout(Dsymbol) pastMixin() inout
510 {
511 //printf("Dsymbol::pastMixin() %s\n", toChars());
512 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
513 return this;
514 if (!parent)
515 return null;
516 return parent.pastMixin();
517 }
518
519 /**********************************
520 * `parent` field returns a lexically enclosing scope symbol this is a member of.
521 *
522 * `toParent()` returns a logically enclosing scope symbol this is a member of.
523 * It skips over TemplateMixin's.
524 *
525 * `toParent2()` returns an enclosing scope symbol this is living at runtime.
526 * It skips over both TemplateInstance's and TemplateMixin's.
527 * It's used when looking for the 'this' pointer of the enclosing function/class.
528 *
529 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
530 * instead of the instantiation scope.
531 *
532 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
533 * if a template declaration is non-local i.e. global or static.
534 *
535 * Examples:
536 * ---
537 * module mod;
538 * template Foo(alias a) { mixin Bar!(); }
539 * mixin template Bar() {
540 * public { // VisibilityDeclaration
541 * void baz() { a = 2; }
542 * }
543 * }
544 * void test() {
545 * int v = 1;
546 * alias foo = Foo!(v);
547 * foo.baz();
548 * assert(v == 2);
549 * }
550 *
551 * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
552 * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
553 * // s.toParent() == TemplateInstance('mod.test.Foo!()')
554 * // s.toParent2() == FuncDeclaration('mod.test')
555 * // s.toParentDecl() == Module('mod')
556 * // s.toParentLocal() == FuncDeclaration('mod.test')
557 * ---
558 */
inout(Dsymbol)559 final inout(Dsymbol) toParent() inout
560 {
561 return parent ? parent.pastMixin() : null;
562 }
563
564 /// ditto
inout(Dsymbol)565 final inout(Dsymbol) toParent2() inout
566 {
567 if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
568 return parent;
569 return parent.toParent2;
570 }
571
572 /// ditto
inout(Dsymbol)573 final inout(Dsymbol) toParentDecl() inout
574 {
575 return toParentDeclImpl(false);
576 }
577
578 /// ditto
inout(Dsymbol)579 final inout(Dsymbol) toParentLocal() inout
580 {
581 return toParentDeclImpl(true);
582 }
583
inout(Dsymbol)584 private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
585 {
586 auto p = toParent();
587 if (!p || !p.isTemplateInstance())
588 return p;
589 auto ti = p.isTemplateInstance();
590 if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
591 return ti.tempdecl.toParentDeclImpl(localOnly);
592 return parent.toParentDeclImpl(localOnly);
593 }
594
595 /**
596 * Returns the declaration scope scope of `this` unless any of the symbols
597 * `p1` or `p2` resides in its enclosing instantiation scope then the
598 * latter is returned.
599 */
600 final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
601 {
602 return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
603 }
604
inout(TemplateInstance)605 final inout(TemplateInstance) isInstantiated() inout
606 {
607 if (!parent)
608 return null;
609 auto ti = parent.isTemplateInstance();
610 if (ti && !ti.isTemplateMixin())
611 return ti;
612 return parent.isInstantiated();
613 }
614
615 /***
616 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
617 * instantiation scope of `this`.
618 */
619 final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
620 {
has2This(Dsymbol s)621 static bool has2This(Dsymbol s)
622 {
623 if (auto f = s.isFuncDeclaration())
624 return f.hasDualContext();
625 if (auto ad = s.isAggregateDeclaration())
626 return ad.vthis2 !is null;
627 return false;
628 }
629
630 if (has2This(this))
631 {
632 assert(p1);
633 auto outer = toParent();
634 while (outer)
635 {
636 auto ti = outer.isTemplateInstance();
637 if (!ti)
638 break;
639 foreach (oarg; *ti.tiargs)
640 {
641 auto sa = getDsymbol(oarg);
642 if (!sa)
643 continue;
644 sa = sa.toAlias().toParent2();
645 if (!sa)
646 continue;
647 if (sa == p1)
648 return true;
649 else if (p2 && sa == p2)
650 return true;
651 }
652 outer = ti.tempdecl.toParent();
653 }
654 return false;
655 }
656 return false;
657 }
658
659 // Check if this function is a member of a template which has only been
660 // instantiated speculatively, eg from inside is(typeof()).
661 // Return the speculative template instance it is part of,
662 // or NULL if not speculative.
inout(TemplateInstance)663 final inout(TemplateInstance) isSpeculative() inout
664 {
665 if (!parent)
666 return null;
667 auto ti = parent.isTemplateInstance();
668 if (ti && ti.gagged)
669 return ti;
670 if (!parent.toParent())
671 return null;
672 return parent.isSpeculative();
673 }
674
ungagSpeculative()675 final Ungag ungagSpeculative() const
676 {
677 uint oldgag = global.gag;
678 if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
679 global.gag = 0;
680 return Ungag(oldgag);
681 }
682
683 // kludge for template.isSymbol()
dyncast()684 override final DYNCAST dyncast() const
685 {
686 return DYNCAST.dsymbol;
687 }
688
689 /*************************************
690 * Do syntax copy of an array of Dsymbol's.
691 */
arraySyntaxCopy(Dsymbols * a)692 extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
693 {
694 Dsymbols* b = null;
695 if (a)
696 {
697 b = a.copy();
698 for (size_t i = 0; i < b.dim; i++)
699 {
700 (*b)[i] = (*b)[i].syntaxCopy(null);
701 }
702 }
703 return b;
704 }
705
getIdent()706 Identifier getIdent()
707 {
708 return ident;
709 }
710
711 const(char)* toPrettyChars(bool QualifyTypes = false)
712 {
713 if (prettystring && !QualifyTypes)
714 return prettystring;
715
716 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
717 if (!parent)
718 {
719 auto s = toChars();
720 if (!QualifyTypes)
721 prettystring = s;
722 return s;
723 }
724
725 // Computer number of components
726 size_t complength = 0;
727 for (Dsymbol p = this; p; p = p.parent)
728 ++complength;
729
730 // Allocate temporary array comp[]
731 alias T = const(char)[];
732 auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
733 auto comp = compptr[0 .. complength];
734
735 // Fill in comp[] and compute length of final result
736 size_t length = 0;
737 int i;
738 for (Dsymbol p = this; p; p = p.parent)
739 {
740 const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
741 const len = strlen(s);
742 comp[i] = s[0 .. len];
743 ++i;
744 length += len + 1;
745 }
746
747 auto s = cast(char*)mem.xmalloc_noscan(length);
748 auto q = s + length - 1;
749 *q = 0;
750 foreach (j; 0 .. complength)
751 {
752 const t = comp[j].ptr;
753 const len = comp[j].length;
754 q -= len;
755 memcpy(q, t, len);
756 if (q == s)
757 break;
758 *--q = '.';
759 }
760 free(comp.ptr);
761 if (!QualifyTypes)
762 prettystring = s;
763 return s;
764 }
765
kind()766 const(char)* kind() const pure nothrow @nogc @safe
767 {
768 return "symbol";
769 }
770
771 /*********************************
772 * If this symbol is really an alias for another,
773 * return that other.
774 * If needed, semantic() is invoked due to resolve forward reference.
775 */
toAlias()776 Dsymbol toAlias()
777 {
778 return this;
779 }
780
781 /*********************************
782 * Resolve recursive tuple expansion in eponymous template.
783 */
toAlias2()784 Dsymbol toAlias2()
785 {
786 return toAlias();
787 }
788
addMember(Scope * sc,ScopeDsymbol sds)789 void addMember(Scope* sc, ScopeDsymbol sds)
790 {
791 //printf("Dsymbol::addMember('%s')\n", toChars());
792 //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
793 //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
794 parent = sds;
795 if (isAnonymous()) // no name, so can't add it to symbol table
796 return;
797
798 if (!sds.symtabInsert(this)) // if name is already defined
799 {
800 if (isAliasDeclaration() && !_scope)
801 setScope(sc);
802 Dsymbol s2 = sds.symtabLookup(this,ident);
803 /* https://issues.dlang.org/show_bug.cgi?id=17434
804 *
805 * If we are trying to add an import to the symbol table
806 * that has already been introduced, then keep the one with
807 * larger visibility. This is fine for imports because if
808 * we have multiple imports of the same file, if a single one
809 * is public then the symbol is reachable.
810 */
811 if (auto i1 = isImport())
812 {
813 if (auto i2 = s2.isImport())
814 {
815 if (sc.explicitVisibility && sc.visibility > i2.visibility)
816 sds.symtab.update(this);
817 }
818 }
819
820 // If using C tag/prototype/forward declaration rules
821 if (sc.flags & SCOPE.Cfile && !this.isImport())
822 {
823 if (handleTagSymbols(*sc, this, s2, sds))
824 return;
825 if (handleSymbolRedeclarations(*sc, this, s2, sds))
826 return;
827
828 sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
829 errors = true;
830 return;
831 }
832
833 if (!s2.overloadInsert(this))
834 {
835 sds.multiplyDefined(Loc.initial, this, s2);
836 errors = true;
837 }
838 }
839 if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
840 {
841 if (ident == Id.__sizeof ||
842 !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
843 {
844 error("`.%s` property cannot be redefined", ident.toChars());
845 errors = true;
846 }
847 }
848 }
849
850 /*************************************
851 * Set scope for future semantic analysis so we can
852 * deal better with forward references.
853 */
setScope(Scope * sc)854 void setScope(Scope* sc)
855 {
856 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
857 if (!sc.nofree)
858 sc.setNoFree(); // may need it even after semantic() finishes
859 _scope = sc;
860 if (sc.depdecl)
861 depdecl = sc.depdecl;
862 if (!userAttribDecl)
863 userAttribDecl = sc.userAttribDecl;
864 }
865
importAll(Scope * sc)866 void importAll(Scope* sc)
867 {
868 }
869
870 /*********************************************
871 * Search for ident as member of s.
872 * Params:
873 * loc = location to print for error messages
874 * ident = identifier to search for
875 * flags = IgnoreXXXX
876 * Returns:
877 * null if not found
878 */
879 Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
880 {
881 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
882 return null;
883 }
884
search_correct(Identifier ident)885 extern (D) final Dsymbol search_correct(Identifier ident)
886 {
887 /***************************************************
888 * Search for symbol with correct spelling.
889 */
890 extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
891 {
892 /* If not in the lexer's string table, it certainly isn't in the symbol table.
893 * Doing this first is a lot faster.
894 */
895 if (!seed.length)
896 return null;
897 Identifier id = Identifier.lookup(seed);
898 if (!id)
899 return null;
900 cost = 0; // all the same cost
901 Dsymbol s = this;
902 Module.clearCache();
903 return s.search(Loc.initial, id, IgnoreErrors);
904 }
905
906 if (global.gag)
907 return null; // don't do it for speculative compiles; too time consuming
908 // search for exact name first
909 if (auto s = search(Loc.initial, ident, IgnoreErrors))
910 return s;
911 return speller!symbol_search_fp(ident.toString());
912 }
913
914 /***************************************
915 * Search for identifier id as a member of `this`.
916 * `id` may be a template instance.
917 *
918 * Params:
919 * loc = location to print the error messages
920 * sc = the scope where the symbol is located
921 * id = the id of the symbol
922 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
923 *
924 * Returns:
925 * symbol found, NULL if not
926 */
searchX(const ref Loc loc,Scope * sc,RootObject id,int flags)927 extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
928 {
929 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
930 Dsymbol s = toAlias();
931 Dsymbol sm;
932 if (Declaration d = s.isDeclaration())
933 {
934 if (d.inuse)
935 {
936 .error(loc, "circular reference to `%s`", d.toPrettyChars());
937 return null;
938 }
939 }
940 switch (id.dyncast())
941 {
942 case DYNCAST.identifier:
943 sm = s.search(loc, cast(Identifier)id, flags);
944 break;
945 case DYNCAST.dsymbol:
946 {
947 // It's a template instance
948 //printf("\ttemplate instance id\n");
949 Dsymbol st = cast(Dsymbol)id;
950 TemplateInstance ti = st.isTemplateInstance();
951 sm = s.search(loc, ti.name);
952 if (!sm)
953 return null;
954 sm = sm.toAlias();
955 TemplateDeclaration td = sm.isTemplateDeclaration();
956 if (!td)
957 {
958 .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
959 return null;
960 }
961 ti.tempdecl = td;
962 if (!ti.semanticRun)
963 ti.dsymbolSemantic(sc);
964 sm = ti.toAlias();
965 break;
966 }
967 case DYNCAST.type:
968 case DYNCAST.expression:
969 default:
970 assert(0);
971 }
972 return sm;
973 }
974
overloadInsert(Dsymbol s)975 bool overloadInsert(Dsymbol s)
976 {
977 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
978 return false;
979 }
980
981 /*********************************
982 * Returns:
983 * SIZE_INVALID when the size cannot be determined
984 */
size(const ref Loc loc)985 uinteger_t size(const ref Loc loc)
986 {
987 error("Dsymbol `%s` has no size", toChars());
988 return SIZE_INVALID;
989 }
990
isforwardRef()991 bool isforwardRef()
992 {
993 return false;
994 }
995
996 // is a 'this' required to access the member
isThis()997 inout(AggregateDeclaration) isThis() inout
998 {
999 return null;
1000 }
1001
1002 // is Dsymbol exported?
isExport()1003 bool isExport() const
1004 {
1005 return false;
1006 }
1007
1008 // is Dsymbol imported?
isImportedSymbol()1009 bool isImportedSymbol() const
1010 {
1011 return false;
1012 }
1013
1014 // is Dsymbol deprecated?
isDeprecated()1015 bool isDeprecated() @safe @nogc pure nothrow const
1016 {
1017 return false;
1018 }
1019
isOverloadable()1020 bool isOverloadable() const
1021 {
1022 return false;
1023 }
1024
1025 // is this a LabelDsymbol()?
isLabel()1026 LabelDsymbol isLabel()
1027 {
1028 return null;
1029 }
1030
1031 /// Returns an AggregateDeclaration when toParent() is that.
inout(AggregateDeclaration)1032 final inout(AggregateDeclaration) isMember() inout
1033 {
1034 //printf("Dsymbol::isMember() %s\n", toChars());
1035 auto p = toParent();
1036 //printf("parent is %s %s\n", p.kind(), p.toChars());
1037 return p ? p.isAggregateDeclaration() : null;
1038 }
1039
1040 /// Returns an AggregateDeclaration when toParent2() is that.
inout(AggregateDeclaration)1041 final inout(AggregateDeclaration) isMember2() inout
1042 {
1043 //printf("Dsymbol::isMember2() '%s'\n", toChars());
1044 auto p = toParent2();
1045 //printf("parent is %s %s\n", p.kind(), p.toChars());
1046 return p ? p.isAggregateDeclaration() : null;
1047 }
1048
1049 /// Returns an AggregateDeclaration when toParentDecl() is that.
inout(AggregateDeclaration)1050 final inout(AggregateDeclaration) isMemberDecl() inout
1051 {
1052 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1053 auto p = toParentDecl();
1054 //printf("parent is %s %s\n", p.kind(), p.toChars());
1055 return p ? p.isAggregateDeclaration() : null;
1056 }
1057
1058 /// Returns an AggregateDeclaration when toParentLocal() is that.
inout(AggregateDeclaration)1059 final inout(AggregateDeclaration) isMemberLocal() inout
1060 {
1061 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1062 auto p = toParentLocal();
1063 //printf("parent is %s %s\n", p.kind(), p.toChars());
1064 return p ? p.isAggregateDeclaration() : null;
1065 }
1066
1067 // is this a member of a ClassDeclaration?
isClassMember()1068 final ClassDeclaration isClassMember()
1069 {
1070 auto ad = isMember();
1071 return ad ? ad.isClassDeclaration() : null;
1072 }
1073
1074 // is this a type?
getType()1075 Type getType()
1076 {
1077 return null;
1078 }
1079
1080 // need a 'this' pointer?
needThis()1081 bool needThis()
1082 {
1083 return false;
1084 }
1085
1086 /*************************************
1087 */
visible()1088 Visibility visible() pure nothrow @nogc @safe
1089 {
1090 return Visibility(Visibility.Kind.public_);
1091 }
1092
1093 /**************************************
1094 * Copy the syntax.
1095 * Used for template instantiations.
1096 * If s is NULL, allocate the new object, otherwise fill it in.
1097 */
syntaxCopy(Dsymbol s)1098 Dsymbol syntaxCopy(Dsymbol s)
1099 {
1100 printf("%s %s\n", kind(), toChars());
1101 assert(0);
1102 }
1103
1104 /**************************************
1105 * Determine if this symbol is only one.
1106 * Returns:
1107 * false, *ps = NULL: There are 2 or more symbols
1108 * true, *ps = NULL: There are zero symbols
1109 * true, *ps = symbol: The one and only one symbol
1110 */
oneMember(Dsymbol * ps,Identifier ident)1111 bool oneMember(Dsymbol* ps, Identifier ident)
1112 {
1113 //printf("Dsymbol::oneMember()\n");
1114 *ps = this;
1115 return true;
1116 }
1117
1118 /*****************************************
1119 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1120 */
oneMembers(Dsymbols * members,Dsymbol * ps,Identifier ident)1121 extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
1122 {
1123 //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1124 Dsymbol s = null;
1125 if (!members)
1126 {
1127 *ps = null;
1128 return true;
1129 }
1130
1131 for (size_t i = 0; i < members.dim; i++)
1132 {
1133 Dsymbol sx = (*members)[i];
1134 bool x = sx.oneMember(ps, ident);
1135 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1136 if (!x)
1137 {
1138 //printf("\tfalse 1\n");
1139 assert(*ps is null);
1140 return false;
1141 }
1142 if (*ps)
1143 {
1144 assert(ident);
1145 if (!(*ps).ident || !(*ps).ident.equals(ident))
1146 continue;
1147 if (!s)
1148 s = *ps;
1149 else if (s.isOverloadable() && (*ps).isOverloadable())
1150 {
1151 // keep head of overload set
1152 FuncDeclaration f1 = s.isFuncDeclaration();
1153 FuncDeclaration f2 = (*ps).isFuncDeclaration();
1154 if (f1 && f2)
1155 {
1156 assert(!f1.isFuncAliasDeclaration());
1157 assert(!f2.isFuncAliasDeclaration());
1158 for (; f1 != f2; f1 = f1.overnext0)
1159 {
1160 if (f1.overnext0 is null)
1161 {
1162 f1.overnext0 = f2;
1163 break;
1164 }
1165 }
1166 }
1167 }
1168 else // more than one symbol
1169 {
1170 *ps = null;
1171 //printf("\tfalse 2\n");
1172 return false;
1173 }
1174 }
1175 }
1176 *ps = s; // s is the one symbol, null if none
1177 //printf("\ttrue\n");
1178 return true;
1179 }
1180
setFieldOffset(AggregateDeclaration ad,ref FieldState fieldState,bool isunion)1181 void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
1182 {
1183 }
1184
1185 /*****************************************
1186 * Is Dsymbol a variable that contains pointers?
1187 */
hasPointers()1188 bool hasPointers()
1189 {
1190 //printf("Dsymbol::hasPointers() %s\n", toChars());
1191 return false;
1192 }
1193
hasStaticCtorOrDtor()1194 bool hasStaticCtorOrDtor()
1195 {
1196 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1197 return false;
1198 }
1199
addLocalClass(ClassDeclarations *)1200 void addLocalClass(ClassDeclarations*)
1201 {
1202 }
1203
addObjcSymbols(ClassDeclarations * classes,ClassDeclarations * categories)1204 void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1205 {
1206 }
1207
checkCtorConstInit()1208 void checkCtorConstInit()
1209 {
1210 }
1211
1212 /****************************************
1213 * Add documentation comment to Dsymbol.
1214 * Ignore NULL comments.
1215 */
addComment(const (char)* comment)1216 void addComment(const(char)* comment)
1217 {
1218 if (!comment || !*comment)
1219 return;
1220
1221 //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
1222 void* h = cast(void*)this; // just the pointer is the key
1223 auto p = h in commentHashTable;
1224 if (!p)
1225 {
1226 commentHashTable[h] = comment;
1227 return;
1228 }
1229 if (strcmp(*p, comment) != 0)
1230 {
1231 // Concatenate the two
1232 *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
1233 }
1234 }
1235
1236 /// get documentation comment for this Dsymbol
comment()1237 final const(char)* comment()
1238 {
1239 //printf("getcomment: %p '%s'\n", this, this.toChars());
1240 if (auto p = cast(void*)this in commentHashTable)
1241 {
1242 //printf("comment: '%s'\n", *p);
1243 return *p;
1244 }
1245 return null;
1246 }
1247
1248 /* Shell around addComment() to avoid disruption for the moment */
comment(const (char)* comment)1249 final void comment(const(char)* comment) { addComment(comment); }
1250
1251 private extern (D) __gshared const(char)*[void*] commentHashTable;
1252
1253
1254 /**********************************
1255 * Get ddoc unittest associated with this symbol.
1256 * (only use this with ddoc)
1257 * Returns: ddoc unittest, null if none
1258 */
ddocUnittest()1259 final UnitTestDeclaration ddocUnittest()
1260 {
1261 if (auto p = cast(void*)this in ddocUnittestHashTable)
1262 return *p;
1263 return null;
1264 }
1265
1266 /**********************************
1267 * Set ddoc unittest associated with this symbol.
1268 */
ddocUnittest(UnitTestDeclaration utd)1269 final void ddocUnittest(UnitTestDeclaration utd)
1270 {
1271 ddocUnittestHashTable[cast(void*)this] = utd;
1272 }
1273
1274 private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable;
1275
1276
1277 /****************************************
1278 * Returns true if this symbol is defined in a non-root module without instantiation.
1279 */
inNonRoot()1280 final bool inNonRoot()
1281 {
1282 Dsymbol s = parent;
1283 for (; s; s = s.toParent())
1284 {
1285 if (auto ti = s.isTemplateInstance())
1286 {
1287 return false;
1288 }
1289 if (auto m = s.isModule())
1290 {
1291 if (!m.isRoot())
1292 return true;
1293 break;
1294 }
1295 }
1296 return false;
1297 }
1298
1299 /**
1300 * Deinitializes the global state of the compiler.
1301 *
1302 * This can be used to restore the state set by `_init` to its original
1303 * state.
1304 */
deinitialize()1305 static void deinitialize()
1306 {
1307 commentHashTable = commentHashTable.init;
1308 ddocUnittestHashTable = ddocUnittestHashTable.init;
1309 }
1310
1311 /************
1312 */
accept(Visitor v)1313 override void accept(Visitor v)
1314 {
1315 v.visit(this);
1316 }
1317
1318 pure nothrow @safe @nogc:
1319
1320 // Eliminate need for dynamic_cast
inout(Package)1321 inout(Package) isPackage() inout { return null; }
isModule()1322 inout(Module) isModule() inout { return null; }
isEnumMember()1323 inout(EnumMember) isEnumMember() inout { return null; }
isTemplateDeclaration()1324 inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
isTemplateInstance()1325 inout(TemplateInstance) isTemplateInstance() inout { return null; }
isTemplateMixin()1326 inout(TemplateMixin) isTemplateMixin() inout { return null; }
isForwardingAttribDeclaration()1327 inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
isNspace()1328 inout(Nspace) isNspace() inout { return null; }
isDeclaration()1329 inout(Declaration) isDeclaration() inout { return null; }
isStorageClassDeclaration()1330 inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
isExpressionDsymbol()1331 inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
isAliasAssign()1332 inout(AliasAssign) isAliasAssign() inout { return null; }
isThisDeclaration()1333 inout(ThisDeclaration) isThisDeclaration() inout { return null; }
isBitFieldDeclaration()1334 inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
isTypeInfoDeclaration()1335 inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
isTupleDeclaration()1336 inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
isAliasDeclaration()1337 inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
isAggregateDeclaration()1338 inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
isFuncDeclaration()1339 inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
isFuncAliasDeclaration()1340 inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
isOverDeclaration()1341 inout(OverDeclaration) isOverDeclaration() inout { return null; }
isFuncLiteralDeclaration()1342 inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
isCtorDeclaration()1343 inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
isPostBlitDeclaration()1344 inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
isDtorDeclaration()1345 inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
isStaticCtorDeclaration()1346 inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
isStaticDtorDeclaration()1347 inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
isSharedStaticCtorDeclaration()1348 inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
isSharedStaticDtorDeclaration()1349 inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
isInvariantDeclaration()1350 inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
isUnitTestDeclaration()1351 inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
isNewDeclaration()1352 inout(NewDeclaration) isNewDeclaration() inout { return null; }
isVarDeclaration()1353 inout(VarDeclaration) isVarDeclaration() inout { return null; }
isVersionSymbol()1354 inout(VersionSymbol) isVersionSymbol() inout { return null; }
isDebugSymbol()1355 inout(DebugSymbol) isDebugSymbol() inout { return null; }
isClassDeclaration()1356 inout(ClassDeclaration) isClassDeclaration() inout { return null; }
isStructDeclaration()1357 inout(StructDeclaration) isStructDeclaration() inout { return null; }
isUnionDeclaration()1358 inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
isInterfaceDeclaration()1359 inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
isScopeDsymbol()1360 inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
isForwardingScopeDsymbol()1361 inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
isWithScopeSymbol()1362 inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
isArrayScopeSymbol()1363 inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
isImport()1364 inout(Import) isImport() inout { return null; }
isEnumDeclaration()1365 inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
isSymbolDeclaration()1366 inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
isAttribDeclaration()1367 inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
isAnonDeclaration()1368 inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
isCPPNamespaceDeclaration()1369 inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
isVisibilityDeclaration()1370 inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
isOverloadSet()1371 inout(OverloadSet) isOverloadSet() inout { return null; }
isCompileDeclaration()1372 inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
isStaticAssert()1373 inout(StaticAssert) isStaticAssert() inout { return null; }
1374 }
1375
1376 /***********************************************************
1377 * Dsymbol that generates a scope
1378 */
1379 extern (C++) class ScopeDsymbol : Dsymbol
1380 {
1381 Dsymbols* members; // all Dsymbol's in this scope
1382 DsymbolTable symtab; // members[] sorted into table
1383 uint endlinnum; // the linnumber of the statement after the scope (0 if unknown)
1384
1385 private:
1386 /// symbols whose members have been imported, i.e. imported modules and template mixins
1387 Dsymbols* importedScopes;
1388 Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
1389
1390 import dmd.root.bitarray;
1391 BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1392
1393 public:
final(D)1394 final extern (D) this() nothrow
1395 {
1396 }
1397
this(Identifier ident)1398 final extern (D) this(Identifier ident) nothrow
1399 {
1400 super(ident);
1401 }
1402
this(const ref Loc loc,Identifier ident)1403 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
1404 {
1405 super(loc, ident);
1406 }
1407
syntaxCopy(Dsymbol s)1408 override ScopeDsymbol syntaxCopy(Dsymbol s)
1409 {
1410 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1411 ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1412 sds.comment = comment;
1413 sds.members = arraySyntaxCopy(members);
1414 sds.endlinnum = endlinnum;
1415 return sds;
1416 }
1417
1418 /*****************************************
1419 * This function is #1 on the list of functions that eat cpu time.
1420 * Be very, very careful about slowing it down.
1421 */
1422 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1423 {
1424 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1425 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1426
1427 // Look in symbols declared in this module
1428 if (symtab && !(flags & SearchImportsOnly))
1429 {
1430 //printf(" look in locals\n");
1431 auto s1 = symtab.lookup(ident);
1432 if (s1)
1433 {
1434 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1435 return s1;
1436 }
1437 }
1438 //printf(" not found in locals\n");
1439
1440 // Look in imported scopes
1441 if (!importedScopes)
1442 return null;
1443
1444 //printf(" look in imports\n");
1445 Dsymbol s = null;
1446 OverloadSet a = null;
1447 // Look in imported modules
1448 for (size_t i = 0; i < importedScopes.dim; i++)
1449 {
1450 // If private import, don't search it
1451 if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
1452 continue;
1453 int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
1454 Dsymbol ss = (*importedScopes)[i];
1455 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1456
1457 if (ss.isModule())
1458 {
1459 if (flags & SearchLocalsOnly)
1460 continue;
1461 }
1462 else // mixin template
1463 {
1464 if (flags & SearchImportsOnly)
1465 continue;
1466
1467 sflags |= SearchLocalsOnly;
1468 }
1469
1470 /* Don't find private members if ss is a module
1471 */
1472 Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1473 import dmd.access : symbolIsVisible;
1474 if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1475 continue;
1476 if (!s)
1477 {
1478 s = s2;
1479 if (s && s.isOverloadSet())
1480 a = mergeOverloadSet(ident, a, s);
1481 }
1482 else if (s2 && s != s2)
1483 {
1484 if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1485 {
1486 /* After following aliases, we found the same
1487 * symbol, so it's not an ambiguity. But if one
1488 * alias is deprecated or less accessible, prefer
1489 * the other.
1490 */
1491 if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
1492 s = s2;
1493 }
1494 else
1495 {
1496 /* Two imports of the same module should be regarded as
1497 * the same.
1498 */
1499 Import i1 = s.isImport();
1500 Import i2 = s2.isImport();
1501 if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1502 {
1503 /* https://issues.dlang.org/show_bug.cgi?id=8668
1504 * Public selective import adds AliasDeclaration in module.
1505 * To make an overload set, resolve aliases in here and
1506 * get actual overload roots which accessible via s and s2.
1507 */
1508 s = s.toAlias();
1509 s2 = s2.toAlias();
1510 /* If both s2 and s are overloadable (though we only
1511 * need to check s once)
1512 */
1513
1514 auto so2 = s2.isOverloadSet();
1515 if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
1516 {
1517 if (symbolIsVisible(this, s2))
1518 {
1519 a = mergeOverloadSet(ident, a, s2);
1520 }
1521 if (!symbolIsVisible(this, s))
1522 s = s2;
1523 continue;
1524 }
1525
1526 /* Two different overflow sets can have the same members
1527 * https://issues.dlang.org/show_bug.cgi?id=16709
1528 */
1529 auto so = s.isOverloadSet();
1530 if (so && so2)
1531 {
1532 if (so.a.length == so2.a.length)
1533 {
1534 foreach (j; 0 .. so.a.length)
1535 {
1536 if (so.a[j] !is so2.a[j])
1537 goto L1;
1538 }
1539 continue; // the same
1540 L1:
1541 { } // different
1542 }
1543 }
1544
1545 if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1546 return null;
1547 if (!(flags & IgnoreErrors))
1548 ScopeDsymbol.multiplyDefined(loc, s, s2);
1549 break;
1550 }
1551 }
1552 }
1553 }
1554 if (s)
1555 {
1556 /* Build special symbol if we had multiple finds
1557 */
1558 if (a)
1559 {
1560 if (!s.isOverloadSet())
1561 a = mergeOverloadSet(ident, a, s);
1562 s = a;
1563 }
1564 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1565 return s;
1566 }
1567 //printf(" not found in imports\n");
1568 return null;
1569 }
1570
mergeOverloadSet(Identifier ident,OverloadSet os,Dsymbol s)1571 extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1572 {
1573 if (!os)
1574 {
1575 os = new OverloadSet(ident);
1576 os.parent = this;
1577 }
1578 if (OverloadSet os2 = s.isOverloadSet())
1579 {
1580 // Merge the cross-module overload set 'os2' into 'os'
1581 if (os.a.dim == 0)
1582 {
1583 os.a.setDim(os2.a.dim);
1584 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1585 }
1586 else
1587 {
1588 for (size_t i = 0; i < os2.a.dim; i++)
1589 {
1590 os = mergeOverloadSet(ident, os, os2.a[i]);
1591 }
1592 }
1593 }
1594 else
1595 {
1596 assert(s.isOverloadable());
1597 /* Don't add to os[] if s is alias of previous sym
1598 */
1599 for (size_t j = 0; j < os.a.dim; j++)
1600 {
1601 Dsymbol s2 = os.a[j];
1602 if (s.toAlias() == s2.toAlias())
1603 {
1604 if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
1605 {
1606 os.a[j] = s;
1607 }
1608 goto Lcontinue;
1609 }
1610 }
1611 os.push(s);
1612 Lcontinue:
1613 }
1614 return os;
1615 }
1616
importScope(Dsymbol s,Visibility visibility)1617 void importScope(Dsymbol s, Visibility visibility) nothrow
1618 {
1619 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1620 // No circular or redundant import's
1621 if (s != this)
1622 {
1623 if (!importedScopes)
1624 importedScopes = new Dsymbols();
1625 else
1626 {
1627 for (size_t i = 0; i < importedScopes.dim; i++)
1628 {
1629 Dsymbol ss = (*importedScopes)[i];
1630 if (ss == s) // if already imported
1631 {
1632 if (visibility.kind > visibilities[i])
1633 visibilities[i] = visibility.kind; // upgrade access
1634 return;
1635 }
1636 }
1637 }
1638 importedScopes.push(s);
1639 visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.dim * (visibilities[0]).sizeof);
1640 visibilities[importedScopes.dim - 1] = visibility.kind;
1641 }
1642 }
1643
addAccessiblePackage(Package p,Visibility visibility)1644 extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
1645 {
1646 auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1647 if (pary.length <= p.tag)
1648 pary.length = p.tag + 1;
1649 (*pary)[p.tag] = true;
1650 }
1651
1652 bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
1653 {
1654 if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1655 visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1656 return true;
1657 foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1658 {
1659 // only search visible scopes && imported modules should ignore private imports
1660 if (visibility.kind <= visibilities[i] &&
1661 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
1662 return true;
1663 }
1664 return false;
1665 }
1666
isforwardRef()1667 override final bool isforwardRef() nothrow
1668 {
1669 return (members is null);
1670 }
1671
multiplyDefined(const ref Loc loc,Dsymbol s1,Dsymbol s2)1672 static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1673 {
1674 version (none)
1675 {
1676 printf("ScopeDsymbol::multiplyDefined()\n");
1677 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1678 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1679 }
1680 if (loc.isValid())
1681 {
1682 .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
1683 s1.kind(), s1.toPrettyChars(), s1.locToChars(),
1684 s2.kind(), s2.toPrettyChars(), s2.locToChars());
1685
1686 static if (0)
1687 {
1688 if (auto so = s1.isOverloadSet())
1689 {
1690 printf("first %p:\n", so);
1691 foreach (s; so.a[])
1692 {
1693 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1694 }
1695 }
1696 if (auto so = s2.isOverloadSet())
1697 {
1698 printf("second %p:\n", so);
1699 foreach (s; so.a[])
1700 {
1701 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1702 }
1703 }
1704 }
1705 }
1706 else
1707 {
1708 s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1709 }
1710 }
1711
kind()1712 override const(char)* kind() const
1713 {
1714 return "ScopeDsymbol";
1715 }
1716
1717 /*******************************************
1718 * Look for member of the form:
1719 * const(MemberInfo)[] getMembers(string);
1720 * Returns NULL if not found
1721 */
findGetMembers()1722 final FuncDeclaration findGetMembers()
1723 {
1724 Dsymbol s = search_function(this, Id.getmembers);
1725 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1726 version (none)
1727 {
1728 // Finish
1729 __gshared TypeFunction tfgetmembers;
1730 if (!tfgetmembers)
1731 {
1732 Scope sc;
1733 auto parameters = new Parameters();
1734 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1735 parameters.push(p);
1736 Type tret = null;
1737 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1738 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1739 }
1740 if (fdx)
1741 fdx = fdx.overloadExactMatch(tfgetmembers);
1742 }
1743 if (fdx && fdx.isVirtual())
1744 fdx = null;
1745 return fdx;
1746 }
1747
1748 /********************************
1749 * Insert Dsymbol in table.
1750 * Params:
1751 * s = symbol to add
1752 * Returns:
1753 * null if already in table, `s` if inserted
1754 */
symtabInsert(Dsymbol s)1755 Dsymbol symtabInsert(Dsymbol s) nothrow
1756 {
1757 return symtab.insert(s);
1758 }
1759
1760 /****************************************
1761 * Look up identifier in symbol table.
1762 * Params:
1763 * s = symbol
1764 * id = identifier to look up
1765 * Returns:
1766 * Dsymbol if found, null if not
1767 */
symtabLookup(Dsymbol s,Identifier id)1768 Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
1769 {
1770 return symtab.lookup(id);
1771 }
1772
1773 /****************************************
1774 * Return true if any of the members are static ctors or static dtors, or if
1775 * any members have members that are.
1776 */
hasStaticCtorOrDtor()1777 override bool hasStaticCtorOrDtor()
1778 {
1779 if (members)
1780 {
1781 for (size_t i = 0; i < members.dim; i++)
1782 {
1783 Dsymbol member = (*members)[i];
1784 if (member.hasStaticCtorOrDtor())
1785 return true;
1786 }
1787 }
1788 return false;
1789 }
1790
1791 extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1792
1793 /***************************************
1794 * Expands attribute declarations in members in depth first
1795 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1796 * member.
1797 * If dg returns !=0, stops and returns that value else returns 0.
1798 * Use this function to avoid the O(N + N^2/2) complexity of
1799 * calculating dim and calling N times getNth.
1800 * Returns:
1801 * last value returned by dg()
1802 */
1803 extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1804 {
1805 assert(dg);
1806 if (!members)
1807 return 0;
1808 size_t n = pn ? *pn : 0; // take over index
1809 int result = 0;
1810 foreach (size_t i; 0 .. members.dim)
1811 {
1812 Dsymbol s = (*members)[i];
1813 if (AttribDeclaration a = s.isAttribDeclaration())
1814 result = _foreach(sc, a.include(sc), dg, &n);
1815 else if (TemplateMixin tm = s.isTemplateMixin())
1816 result = _foreach(sc, tm.members, dg, &n);
1817 else if (s.isTemplateInstance())
1818 {
1819 }
1820 else if (s.isUnitTestDeclaration())
1821 {
1822 }
1823 else
1824 result = dg(n++, s);
1825 if (result)
1826 break;
1827 }
1828 if (pn)
1829 *pn = n; // update index
1830 return result;
1831 }
1832
inout(ScopeDsymbol)1833 override final inout(ScopeDsymbol) isScopeDsymbol() inout
1834 {
1835 return this;
1836 }
1837
accept(Visitor v)1838 override void accept(Visitor v)
1839 {
1840 v.visit(this);
1841 }
1842 }
1843
1844 /***********************************************************
1845 * With statement scope
1846 */
1847 extern (C++) final class WithScopeSymbol : ScopeDsymbol
1848 {
1849 WithStatement withstate;
1850
this(WithStatement withstate)1851 extern (D) this(WithStatement withstate) nothrow
1852 {
1853 this.withstate = withstate;
1854 }
1855
1856 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1857 {
1858 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1859 if (flags & SearchImportsOnly)
1860 return null;
1861 // Acts as proxy to the with class declaration
1862 Dsymbol s = null;
1863 Expression eold = null;
1864 for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
1865 {
1866 if (e.op == EXP.scope_)
1867 {
1868 s = (cast(ScopeExp)e).sds;
1869 }
1870 else if (e.op == EXP.type)
1871 {
1872 s = e.type.toDsymbol(null);
1873 }
1874 else
1875 {
1876 Type t = e.type.toBasetype();
1877 s = t.toDsymbol(null);
1878 }
1879 if (s)
1880 {
1881 s = s.search(loc, ident, flags);
1882 if (s)
1883 return s;
1884 }
1885 eold = e;
1886 }
1887 return null;
1888 }
1889
inout(WithScopeSymbol)1890 override inout(WithScopeSymbol) isWithScopeSymbol() inout
1891 {
1892 return this;
1893 }
1894
accept(Visitor v)1895 override void accept(Visitor v)
1896 {
1897 v.visit(this);
1898 }
1899 }
1900
1901 /***********************************************************
1902 * Array Index/Slice scope
1903 */
1904 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1905 {
1906 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1907 // Discriminated using DYNCAST and, for expressions, also EXP
1908 private RootObject arrayContent;
1909 Scope* sc;
1910
this(Scope * sc,Expression exp)1911 extern (D) this(Scope* sc, Expression exp) nothrow
1912 {
1913 super(exp.loc, null);
1914 assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
1915 this.sc = sc;
1916 this.arrayContent = exp;
1917 }
1918
this(Scope * sc,TypeTuple type)1919 extern (D) this(Scope* sc, TypeTuple type) nothrow
1920 {
1921 this.sc = sc;
1922 this.arrayContent = type;
1923 }
1924
this(Scope * sc,TupleDeclaration td)1925 extern (D) this(Scope* sc, TupleDeclaration td) nothrow
1926 {
1927 this.sc = sc;
1928 this.arrayContent = td;
1929 }
1930
1931 /// This override is used to solve `$`
1932 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
1933 {
1934 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1935 if (ident != Id.dollar)
1936 return null;
1937
1938 VarDeclaration* pvar;
1939 Expression ce;
1940
dollarFromTypeTuple(const ref Loc loc,TypeTuple tt,Scope * sc)1941 static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
1942 {
1943
1944 /* $ gives the number of type entries in the type tuple
1945 */
1946 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1947 Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
1948 v._init = new ExpInitializer(Loc.initial, e);
1949 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1950 v.dsymbolSemantic(sc);
1951 return v;
1952 }
1953
1954 const DYNCAST kind = arrayContent.dyncast();
1955 if (kind == DYNCAST.dsymbol)
1956 {
1957 TupleDeclaration td = cast(TupleDeclaration) arrayContent;
1958 /* $ gives the number of elements in the tuple
1959 */
1960 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1961 Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
1962 v._init = new ExpInitializer(Loc.initial, e);
1963 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1964 v.dsymbolSemantic(sc);
1965 return v;
1966 }
1967 if (kind == DYNCAST.type)
1968 {
1969 return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
1970 }
1971 Expression exp = cast(Expression) arrayContent;
1972 if (auto ie = exp.isIndexExp())
1973 {
1974 /* array[index] where index is some function of $
1975 */
1976 pvar = &ie.lengthVar;
1977 ce = ie.e1;
1978 }
1979 else if (auto se = exp.isSliceExp())
1980 {
1981 /* array[lwr .. upr] where lwr or upr is some function of $
1982 */
1983 pvar = &se.lengthVar;
1984 ce = se.e1;
1985 }
1986 else if (auto ae = exp.isArrayExp())
1987 {
1988 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1989 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1990 */
1991 pvar = &ae.lengthVar;
1992 ce = ae.e1;
1993 }
1994 else
1995 {
1996 /* Didn't find $, look in enclosing scope(s).
1997 */
1998 return null;
1999 }
2000 ce = ce.lastComma();
2001 /* If we are indexing into an array that is really a type
2002 * tuple, rewrite this as an index into a type tuple and
2003 * try again.
2004 */
2005 if (auto te = ce.isTypeExp())
2006 {
2007 if (auto ttp = te.type.isTypeTuple())
2008 return dollarFromTypeTuple(loc, ttp, sc);
2009 }
2010 /* *pvar is lazily initialized, so if we refer to $
2011 * multiple times, it gets set only once.
2012 */
2013 if (!*pvar) // if not already initialized
2014 {
2015 /* Create variable v and set it to the value of $
2016 */
2017 VarDeclaration v;
2018 Type t;
2019 if (auto tupexp = ce.isTupleExp())
2020 {
2021 /* It is for an expression tuple, so the
2022 * length will be a const.
2023 */
2024 Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
2025 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
2026 v.storage_class |= STC.temp | STC.static_ | STC.const_;
2027 }
2028 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
2029 {
2030 // Look for opDollar
2031 assert(exp.op == EXP.array || exp.op == EXP.slice);
2032 AggregateDeclaration ad = isAggregate(t);
2033 assert(ad);
2034 Dsymbol s = ad.search(loc, Id.opDollar);
2035 if (!s) // no dollar exists -- search in higher scope
2036 return null;
2037 s = s.toAlias();
2038 Expression e = null;
2039 // Check for multi-dimensional opDollar(dim) template.
2040 if (TemplateDeclaration td = s.isTemplateDeclaration())
2041 {
2042 dinteger_t dim = 0;
2043 if (exp.op == EXP.array)
2044 {
2045 dim = (cast(ArrayExp)exp).currentDimension;
2046 }
2047 else if (exp.op == EXP.slice)
2048 {
2049 dim = 0; // slices are currently always one-dimensional
2050 }
2051 else
2052 {
2053 assert(0);
2054 }
2055 auto tiargs = new Objects();
2056 Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
2057 edim = edim.expressionSemantic(sc);
2058 tiargs.push(edim);
2059 e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
2060 }
2061 else
2062 {
2063 /* opDollar exists, but it's not a template.
2064 * This is acceptable ONLY for single-dimension indexing.
2065 * Note that it's impossible to have both template & function opDollar,
2066 * because both take no arguments.
2067 */
2068 if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1)
2069 {
2070 exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
2071 return null;
2072 }
2073 Declaration d = s.isDeclaration();
2074 assert(d);
2075 e = new DotVarExp(loc, ce, d);
2076 }
2077 e = e.expressionSemantic(sc);
2078 if (!e.type)
2079 exp.error("`%s` has no value", e.toChars());
2080 t = e.type.toBasetype();
2081 if (t && t.ty == Tfunction)
2082 e = new CallExp(e.loc, e);
2083 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
2084 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
2085 }
2086 else
2087 {
2088 /* For arrays, $ will either be a compile-time constant
2089 * (in which case its value in set during constant-folding),
2090 * or a variable (in which case an expression is created in
2091 * toir.c).
2092 */
2093 auto e = new VoidInitializer(Loc.initial);
2094 e.type = Type.tsize_t;
2095 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
2096 v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
2097 }
2098 *pvar = v;
2099 }
2100 (*pvar).dsymbolSemantic(sc);
2101 return (*pvar);
2102 }
2103
inout(ArrayScopeSymbol)2104 override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
2105 {
2106 return this;
2107 }
2108
accept(Visitor v)2109 override void accept(Visitor v)
2110 {
2111 v.visit(this);
2112 }
2113 }
2114
2115 /***********************************************************
2116 * Overload Sets
2117 */
2118 extern (C++) final class OverloadSet : Dsymbol
2119 {
2120 Dsymbols a; // array of Dsymbols
2121
2122 extern (D) this(Identifier ident, OverloadSet os = null) nothrow
2123 {
2124 super(ident);
2125 if (os)
2126 {
2127 a.pushSlice(os.a[]);
2128 }
2129 }
2130
push(Dsymbol s)2131 void push(Dsymbol s) nothrow
2132 {
2133 a.push(s);
2134 }
2135
inout(OverloadSet)2136 override inout(OverloadSet) isOverloadSet() inout
2137 {
2138 return this;
2139 }
2140
kind()2141 override const(char)* kind() const
2142 {
2143 return "overloadset";
2144 }
2145
accept(Visitor v)2146 override void accept(Visitor v)
2147 {
2148 v.visit(this);
2149 }
2150 }
2151
2152 /***********************************************************
2153 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2154 * ForwardingScopeDeclaration to forward symbol insertions to another
2155 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2156 * details.
2157 */
2158 extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
2159 {
2160 /*************************
2161 * Symbol to forward insertions to.
2162 * Can be `null` before being lazily initialized.
2163 */
2164 ScopeDsymbol forward;
this(ScopeDsymbol forward)2165 extern (D) this(ScopeDsymbol forward) nothrow
2166 {
2167 super(null);
2168 this.forward = forward;
2169 }
2170
symtabInsert(Dsymbol s)2171 override Dsymbol symtabInsert(Dsymbol s) nothrow
2172 {
2173 assert(forward);
2174 if (auto d = s.isDeclaration())
2175 {
2176 if (d.storage_class & STC.local)
2177 {
2178 // Symbols with storage class STC.local are not
2179 // forwarded, but stored in the local symbol
2180 // table. (Those are the `static foreach` variables.)
2181 if (!symtab)
2182 {
2183 symtab = new DsymbolTable();
2184 }
2185 return super.symtabInsert(s); // insert locally
2186 }
2187 }
2188 if (!forward.symtab)
2189 {
2190 forward.symtab = new DsymbolTable();
2191 }
2192 // Non-STC.local symbols are forwarded to `forward`.
2193 return forward.symtabInsert(s);
2194 }
2195
2196 /************************
2197 * This override handles the following two cases:
2198 * static foreach (i, i; [0]) { ... }
2199 * and
2200 * static foreach (i; [0]) { enum i = 2; }
2201 */
symtabLookup(Dsymbol s,Identifier id)2202 override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
2203 {
2204 assert(forward);
2205 // correctly diagnose clashing foreach loop variables.
2206 if (auto d = s.isDeclaration())
2207 {
2208 if (d.storage_class & STC.local)
2209 {
2210 if (!symtab)
2211 {
2212 symtab = new DsymbolTable();
2213 }
2214 return super.symtabLookup(s,id);
2215 }
2216 }
2217 // Declarations within `static foreach` do not clash with
2218 // `static foreach` loop variables.
2219 if (!forward.symtab)
2220 {
2221 forward.symtab = new DsymbolTable();
2222 }
2223 return forward.symtabLookup(s,id);
2224 }
2225
importScope(Dsymbol s,Visibility visibility)2226 override void importScope(Dsymbol s, Visibility visibility)
2227 {
2228 forward.importScope(s, visibility);
2229 }
2230
kind()2231 override const(char)* kind()const{ return "local scope"; }
2232
inout(ForwardingScopeDsymbol)2233 override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
2234 {
2235 return this;
2236 }
2237
2238 }
2239
2240 /**
2241 * Class that holds an expression in a Dsymbol wrapper.
2242 * This is not an AST node, but a class used to pass
2243 * an expression as a function parameter of type Dsymbol.
2244 */
2245 extern (C++) final class ExpressionDsymbol : Dsymbol
2246 {
2247 Expression exp;
this(Expression exp)2248 this(Expression exp) nothrow
2249 {
2250 super();
2251 this.exp = exp;
2252 }
2253
inout(ExpressionDsymbol)2254 override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
2255 {
2256 return this;
2257 }
2258 }
2259
2260 /**********************************************
2261 * Encapsulate assigning to an alias:
2262 * `identifier = type;`
2263 * `identifier = symbol;`
2264 * where `identifier` is an AliasDeclaration in scope.
2265 */
2266 extern (C++) final class AliasAssign : Dsymbol
2267 {
2268 Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
2269 Type type; /// replace previous RHS of AliasDeclaration with `type`
2270 Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
2271 /// only one of type and aliassym can be != null
2272
this(const ref Loc loc,Identifier ident,Type type,Dsymbol aliassym)2273 extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
2274 {
2275 super(loc, null);
2276 this.ident = ident;
2277 this.type = type;
2278 this.aliassym = aliassym;
2279 }
2280
syntaxCopy(Dsymbol s)2281 override AliasAssign syntaxCopy(Dsymbol s)
2282 {
2283 assert(!s);
2284 AliasAssign aa = new AliasAssign(loc, ident,
2285 type ? type.syntaxCopy() : null,
2286 aliassym ? aliassym.syntaxCopy(null) : null);
2287 return aa;
2288 }
2289
inout(AliasAssign)2290 override inout(AliasAssign) isAliasAssign() inout
2291 {
2292 return this;
2293 }
2294
kind()2295 override const(char)* kind() const
2296 {
2297 return "alias assignment";
2298 }
2299
accept(Visitor v)2300 override void accept(Visitor v)
2301 {
2302 v.visit(this);
2303 }
2304 }
2305
2306 /***********************************************************
2307 * Table of Dsymbol's
2308 */
2309 extern (C++) final class DsymbolTable : RootObject
2310 {
2311 AssocArray!(Identifier, Dsymbol) tab;
2312
2313 nothrow:
2314
2315 /***************************
2316 * Look up Identifier in symbol table
2317 * Params:
2318 * ident = identifer to look up
2319 * Returns:
2320 * Dsymbol if found, null if not
2321 */
lookup(const Identifier ident)2322 Dsymbol lookup(const Identifier ident)
2323 {
2324 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2325 return tab[ident];
2326 }
2327
2328 /**********
2329 * Replace existing symbol in symbol table with `s`.
2330 * If it's not there, add it.
2331 * Params:
2332 * s = replacement symbol with same identifier
2333 */
update(Dsymbol s)2334 void update(Dsymbol s)
2335 {
2336 *tab.getLvalue(s.ident) = s;
2337 }
2338
2339 /**************************
2340 * Insert Dsymbol in table.
2341 * Params:
2342 * s = symbol to add
2343 * Returns:
2344 * null if already in table, `s` if inserted
2345 */
insert(Dsymbol s)2346 Dsymbol insert(Dsymbol s)
2347 {
2348 return insert(s.ident, s);
2349 }
2350
2351 /**************************
2352 * Insert Dsymbol in table.
2353 * Params:
2354 * ident = identifier to serve as index
2355 * s = symbol to add
2356 * Returns:
2357 * null if already in table, `s` if inserted
2358 */
insert(const Identifier ident,Dsymbol s)2359 Dsymbol insert(const Identifier ident, Dsymbol s)
2360 {
2361 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2362 Dsymbol* ps = tab.getLvalue(ident);
2363 if (*ps)
2364 return null; // already in table
2365 *ps = s;
2366 return s;
2367 }
2368
2369 /*****************
2370 * Returns:
2371 * number of symbols in symbol table
2372 */
length()2373 size_t length() const pure
2374 {
2375 return tab.length;
2376 }
2377 }
2378
2379 /**********************************************
2380 * ImportC tag symbols sit in a parallel symbol table,
2381 * so that this C code works:
2382 * ---
2383 * struct S { a; };
2384 * int S;
2385 * struct S s;
2386 * ---
2387 * But there are relatively few such tag symbols, so that would be
2388 * a waste of memory and complexity. An additional problem is we'd like the D side
2389 * to find the tag symbols with ordinary lookup, not lookup in both
2390 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2391 * The solution is to put the tag symbols that conflict into an associative
2392 * array, indexed by the address of the ordinary symbol that conflicts with it.
2393 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2394 * A side effect of our approach is that D code cannot access a tag symbol that is
2395 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2396 * has mentioned it when importing C headers. If someone wants to do it,
2397 * too bad so sad. Change the C code.
2398 * This function fixes up the symbol table when faced with adding a new symbol
2399 * `s` when there is an existing symbol `s2` with the same name.
2400 * C also allows forward and prototype declarations of tag symbols,
2401 * this function merges those.
2402 * Params:
2403 * sc = context
2404 * s = symbol to add to symbol table
2405 * s2 = existing declaration
2406 * sds = symbol table
2407 * Returns:
2408 * if s and s2 are successfully put in symbol table then return the merged symbol,
2409 * null if they conflict
2410 */
handleTagSymbols(ref Scope sc,Dsymbol s,Dsymbol s2,ScopeDsymbol sds)2411 Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2412 {
2413 enum log = false;
2414 if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
2415 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2416 auto sd = s.isScopeDsymbol(); // new declaration
2417 auto sd2 = s2.isScopeDsymbol(); // existing declaration
2418
2419 if (!sd2)
2420 {
2421 /* Look in tag table
2422 */
2423 if (log) printf(" look in tag table\n");
2424 if (auto p = cast(void*)s2 in sc._module.tagSymTab)
2425 {
2426 Dsymbol s2tag = *p;
2427 sd2 = s2tag.isScopeDsymbol();
2428 assert(sd2); // only tags allowed in tag symbol table
2429 }
2430 }
2431
2432 if (sd && sd2) // `s` is a tag, `sd2` is the same tag
2433 {
2434 if (log) printf(" tag is already defined\n");
2435
2436 if (sd.kind() != sd2.kind()) // being enum/struct/union must match
2437 return null; // conflict
2438
2439 /* Not a redeclaration if one is a forward declaration.
2440 * Move members to the first declared type, which is sd2.
2441 */
2442 if (sd2.members)
2443 {
2444 if (!sd.members)
2445 return sd2; // ignore the sd redeclaration
2446 }
2447 else if (sd.members)
2448 {
2449 sd2.members = sd.members; // transfer definition to sd2
2450 sd.members = null;
2451 return sd2;
2452 }
2453 else
2454 return sd2; // ignore redeclaration
2455 }
2456 else if (sd) // `s` is a tag, `s2` is not
2457 {
2458 if (log) printf(" s is tag, s2 is not\n");
2459 /* add `s` as tag indexed by s2
2460 */
2461 sc._module.tagSymTab[cast(void*)s2] = s;
2462 return s;
2463 }
2464 else if (s2 is sd2) // `s2` is a tag, `s` is not
2465 {
2466 if (log) printf(" s2 is tag, s is not\n");
2467 /* replace `s2` in symbol table with `s`,
2468 * then add `s2` as tag indexed by `s`
2469 */
2470 sds.symtab.update(s);
2471 sc._module.tagSymTab[cast(void*)s] = s2;
2472 return s;
2473 }
2474 // neither s2 nor s is a tag
2475 if (log) printf(" collision\n");
2476 return null;
2477 }
2478
2479
2480 /**********************************************
2481 * ImportC allows redeclarations of C variables, functions and typedefs.
2482 * extern int x;
2483 * int x = 3;
2484 * and:
2485 * extern void f();
2486 * void f() { }
2487 * Attempt to merge them.
2488 * Params:
2489 * sc = context
2490 * s = symbol to add to symbol table
2491 * s2 = existing declaration
2492 * sds = symbol table
2493 * Returns:
2494 * if s and s2 are successfully put in symbol table then return the merged symbol,
2495 * null if they conflict
2496 */
handleSymbolRedeclarations(ref Scope sc,Dsymbol s,Dsymbol s2,ScopeDsymbol sds)2497 Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2498 {
2499 enum log = false;
2500 if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
2501 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
2502
2503 static Dsymbol collision()
2504 {
2505 if (log) printf(" collision\n");
2506 return null;
2507 }
2508
2509 auto vd = s.isVarDeclaration(); // new declaration
2510 auto vd2 = s2.isVarDeclaration(); // existing declaration
2511 if (vd && vd2)
2512 {
2513 /* if one is `static` and the other isn't, the result is undefined
2514 * behavior, C11 6.2.2.7
2515 */
2516 if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
2517 return collision();
2518
2519 const i1 = vd._init && ! vd._init.isVoidInitializer();
2520 const i2 = vd2._init && !vd2._init.isVoidInitializer();
2521
2522 if (i1 && i2)
2523 return collision(); // can't both have initializers
2524
2525 if (i1) // vd is the definition
2526 {
2527 vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it
2528 sds.symtab.update(vd); // replace vd2 with the definition
2529 return vd;
2530 }
2531
2532 /* BUG: the types should match, which needs semantic() to be run on it
2533 * extern int x;
2534 * int x; // match
2535 * typedef int INT;
2536 * INT x; // match
2537 * long x; // collision
2538 * We incorrectly ignore these collisions
2539 */
2540 return vd2;
2541 }
2542
2543 auto fd = s.isFuncDeclaration(); // new declaration
2544 auto fd2 = s2.isFuncDeclaration(); // existing declaration
2545 if (fd && fd2)
2546 {
2547 /* if one is `static` and the other isn't, the result is undefined
2548 * behavior, C11 6.2.2.7
2549 * However, match what gcc allows:
2550 * static int sun1(); int sun1() { return 0; }
2551 * and:
2552 * static int sun2() { return 0; } int sun2();
2553 * Both produce a static function.
2554 *
2555 * Both of these should fail:
2556 * int sun3(); static int sun3() { return 0; }
2557 * and:
2558 * int sun4() { return 0; } static int sun4();
2559 */
2560 // if adding `static`
2561 if ( fd.storage_class & STC.static_ &&
2562 !(fd2.storage_class & STC.static_))
2563 {
2564 return collision();
2565 }
2566
2567 if (fd.fbody && fd2.fbody)
2568 return collision(); // can't both have bodies
2569
2570 if (fd.fbody) // fd is the definition
2571 {
2572 if (log) printf(" replace existing with new\n");
2573 sds.symtab.update(fd); // replace fd2 in symbol table with fd
2574 fd.overnext = fd2;
2575
2576 /* If fd2 is covering a tag symbol, then fd has to cover the same one
2577 */
2578 auto ps = cast(void*)fd2 in sc._module.tagSymTab;
2579 if (ps)
2580 sc._module.tagSymTab[cast(void*)fd] = *ps;
2581
2582 return fd;
2583 }
2584
2585 /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2586 * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
2587 */
2588 fd2.overloadInsert(fd);
2589
2590 return fd2;
2591 }
2592
2593 auto td = s.isAliasDeclaration(); // new declaration
2594 auto td2 = s2.isAliasDeclaration(); // existing declaration
2595 if (td && td2)
2596 {
2597 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2598 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2599 */
2600 return td2;
2601 }
2602
2603 return collision();
2604 }
2605