]> gcc.gnu.org Git - gcc.git/blame - gcc/d/dmd/dsymbol.d
d: Merge upstream dmd d579c467c1, phobos 88aa69b14.
[gcc.git] / gcc / d / dmd / dsymbol.d
CommitLineData
5fee5ec3
IB
1/**
2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
3 *
c43b5909
IB
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)
5fee5ec3
IB
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
12module dmd.dsymbol;
13
14import core.stdc.stdarg;
15import core.stdc.stdio;
16import core.stdc.string;
17import core.stdc.stdlib;
18
19import dmd.aggregate;
20import dmd.aliasthis;
21import dmd.arraytypes;
22import dmd.attrib;
23import dmd.astenums;
24import dmd.ast_node;
25import dmd.gluelayer;
26import dmd.dclass;
27import dmd.declaration;
28import dmd.denum;
29import dmd.dimport;
30import dmd.dmodule;
31import dmd.dversion;
32import dmd.dscope;
33import dmd.dstruct;
34import dmd.dsymbolsem;
35import dmd.dtemplate;
36import dmd.errors;
37import dmd.expression;
38import dmd.expressionsem;
39import dmd.func;
40import dmd.globals;
41import dmd.id;
42import dmd.identifier;
43import dmd.init;
44import dmd.lexer;
45import dmd.mtype;
46import dmd.nspace;
47import dmd.opover;
48import dmd.root.aav;
49import dmd.root.rmem;
50import dmd.root.rootobject;
51import dmd.root.speller;
52import dmd.root.string;
53import dmd.statement;
6384eff5 54import dmd.staticassert;
5fee5ec3
IB
55import dmd.tokens;
56import 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 */
69int 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 */
95void 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
111struct Ungag
112{
113 uint oldgag;
114
31350635 115 extern (D) this(uint old) nothrow
5fee5ec3
IB
116 {
117 this.oldgag = old;
118 }
119
31350635 120 extern (C++) ~this() nothrow
5fee5ec3
IB
121 {
122 global.gag = oldgag;
123 }
124}
125
126struct 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 */
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 */
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
0fb57034 191enum PASS : ubyte
5fee5ec3 192{
235d5a96 193 initial, // initial state
5fee5ec3
IB
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
206enum : 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 */
227struct FieldState
228{
0fb57034 229 uint offset; /// byte offset for next field
5fee5ec3 230
0fb57034
IB
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
5fee5ec3 234 uint bitOffset; /// bit offset for field
0fb57034 235
5fee5ec3
IB
236 bool inFlight; /// bit field is in flight
237}
238
239/***********************************************************
240 */
241extern (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
5fee5ec3
IB
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()
235d5a96 252 PASS semanticRun = PASS.initial;
5fee5ec3
IB
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
31350635 258 final extern (D) this() nothrow
5fee5ec3
IB
259 {
260 //printf("Dsymbol::Dsymbol(%p)\n", this);
261 loc = Loc(null, 0, 0);
262 }
263
31350635 264 final extern (D) this(Identifier ident) nothrow
5fee5ec3
IB
265 {
266 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
267 this.loc = Loc(null, 0, 0);
268 this.ident = ident;
269 }
270
31350635 271 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
5fee5ec3
IB
272 {
273 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
274 this.loc = loc;
275 this.ident = ident;
276 }
277
31350635 278 static Dsymbol create(Identifier ident) nothrow
5fee5ec3
IB
279 {
280 return new Dsymbol(ident);
281 }
282
283 override const(char)* toChars() const
284 {
285 return ident ? ident.toChars() : "__anonymous";
286 }
287
288 // helper to print fully qualified (template) arguments
289 const(char)* toPrettyCharsHelper()
290 {
291 return toChars();
292 }
293
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
302 final const(char)* locToChars()
303 {
304 return getLoc().toChars();
305 }
306
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
322 final bool isAnonymous() const
323 {
324 return ident is null || ident.isAnonymous;
325 }
326
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 {
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
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
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
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 {
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
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
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
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
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 */
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
fd43568c
IB
460 /**************************************
461 * Does this Dsymbol come from a C file?
462 * Returns:
463 * true if it does
464 */
465 final bool isCsymbol()
466 {
467 if (Module m = getModule())
fbdaa581 468 return m.filetype == FileType.c;
fd43568c
IB
469 return false;
470 }
471
5fee5ec3
IB
472 /**********************************
473 * Determine which Module a Dsymbol is in, as far as access rights go.
474 */
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 */
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 */
559 final inout(Dsymbol) toParent() inout
560 {
561 return parent ? parent.pastMixin() : null;
562 }
563
564 /// ditto
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
573 final inout(Dsymbol) toParentDecl() inout
574 {
575 return toParentDeclImpl(false);
576 }
577
578 /// ditto
579 final inout(Dsymbol) toParentLocal() inout
580 {
581 return toParentDeclImpl(true);
582 }
583
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
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 {
621 static bool has2This(Dsymbol s)
622 {
623 if (auto f = s.isFuncDeclaration())
235d5a96 624 return f.hasDualContext();
5fee5ec3
IB
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.
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
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()
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 */
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
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
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 */
776 Dsymbol toAlias()
777 {
778 return this;
779 }
780
781 /*********************************
782 * Resolve recursive tuple expansion in eponymous template.
783 */
784 Dsymbol toAlias2()
785 {
786 return toAlias();
787 }
788
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);
31350635
IB
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 }
5fee5ec3
IB
819
820 // If using C tag/prototype/forward declaration rules
7e287503 821 if (sc.flags & SCOPE.Cfile && !this.isImport())
0fb57034
IB
822 {
823 if (handleTagSymbols(*sc, this, s2, sds))
824 return;
825 if (handleSymbolRedeclarations(*sc, this, s2, sds))
5fee5ec3
IB
826 return;
827
0fb57034
IB
828 sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
829 errors = true;
830 return;
831 }
832
5fee5ec3
IB
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 {
ae56e2da
IB
841 if (ident == Id.__sizeof ||
842 !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
5fee5ec3
IB
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 */
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
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
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 */
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)
5fee5ec3 953 return null;
5fee5ec3
IB
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
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 */
fbdaa581 985 uinteger_t size(const ref Loc loc)
5fee5ec3 986 {
5eb9927a 987 error("symbol `%s` has no size", toChars());
5fee5ec3
IB
988 return SIZE_INVALID;
989 }
990
991 bool isforwardRef()
992 {
993 return false;
994 }
995
996 // is a 'this' required to access the member
997 inout(AggregateDeclaration) isThis() inout
998 {
999 return null;
1000 }
1001
1002 // is Dsymbol exported?
1003 bool isExport() const
1004 {
1005 return false;
1006 }
1007
1008 // is Dsymbol imported?
1009 bool isImportedSymbol() const
1010 {
1011 return false;
1012 }
1013
1014 // is Dsymbol deprecated?
1015 bool isDeprecated() @safe @nogc pure nothrow const
1016 {
1017 return false;
1018 }
1019
1020 bool isOverloadable() const
1021 {
1022 return false;
1023 }
1024
1025 // is this a LabelDsymbol()?
1026 LabelDsymbol isLabel()
1027 {
1028 return null;
1029 }
1030
1031 /// Returns an AggregateDeclaration when toParent() is that.
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.
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.
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.
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?
1068 final ClassDeclaration isClassMember()
1069 {
1070 auto ad = isMember();
1071 return ad ? ad.isClassDeclaration() : null;
1072 }
1073
1074 // is this a type?
1075 Type getType()
1076 {
1077 return null;
1078 }
1079
1080 // need a 'this' pointer?
1081 bool needThis()
1082 {
1083 return false;
1084 }
1085
1086 /*************************************
1087 */
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 */
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 */
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 */
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
1181 void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
1182 {
1183 }
1184
1185 /*****************************************
1186 * Is Dsymbol a variable that contains pointers?
1187 */
1188 bool hasPointers()
1189 {
1190 //printf("Dsymbol::hasPointers() %s\n", toChars());
1191 return false;
1192 }
1193
1194 bool hasStaticCtorOrDtor()
1195 {
1196 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1197 return false;
1198 }
1199
1200 void addLocalClass(ClassDeclarations*)
1201 {
1202 }
1203
1204 void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1205 {
1206 }
1207
1208 void checkCtorConstInit()
1209 {
1210 }
1211
1212 /****************************************
1213 * Add documentation comment to Dsymbol.
1214 * Ignore NULL comments.
1215 */
1216 void addComment(const(char)* comment)
1217 {
7e287503
IB
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)
5fee5ec3
IB
1230 {
1231 // Concatenate the two
7e287503 1232 *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
5fee5ec3
IB
1233 }
1234 }
1235
7e287503
IB
1236 /// get documentation comment for this Dsymbol
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 */
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 */
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 */
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
5fee5ec3
IB
1277 /****************************************
1278 * Returns true if this symbol is defined in a non-root module without instantiation.
1279 */
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
7e287503
IB
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 */
1305 static void deinitialize()
1306 {
1307 commentHashTable = commentHashTable.init;
1308 ddocUnittestHashTable = ddocUnittestHashTable.init;
1309 }
1310
5fee5ec3
IB
1311 /************
1312 */
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
1321 inout(Package) isPackage() inout { return null; }
1322 inout(Module) isModule() inout { return null; }
1323 inout(EnumMember) isEnumMember() inout { return null; }
1324 inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
1325 inout(TemplateInstance) isTemplateInstance() inout { return null; }
1326 inout(TemplateMixin) isTemplateMixin() inout { return null; }
1327 inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
1328 inout(Nspace) isNspace() inout { return null; }
1329 inout(Declaration) isDeclaration() inout { return null; }
1330 inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
1331 inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
1332 inout(AliasAssign) isAliasAssign() inout { return null; }
1333 inout(ThisDeclaration) isThisDeclaration() inout { return null; }
1334 inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
1335 inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
1336 inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
1337 inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
1338 inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
1339 inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
1340 inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
1341 inout(OverDeclaration) isOverDeclaration() inout { return null; }
1342 inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
1343 inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
1344 inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
1345 inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
1346 inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
1347 inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
1348 inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
1349 inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
1350 inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
1351 inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
1352 inout(NewDeclaration) isNewDeclaration() inout { return null; }
1353 inout(VarDeclaration) isVarDeclaration() inout { return null; }
1354 inout(VersionSymbol) isVersionSymbol() inout { return null; }
1355 inout(DebugSymbol) isDebugSymbol() inout { return null; }
1356 inout(ClassDeclaration) isClassDeclaration() inout { return null; }
1357 inout(StructDeclaration) isStructDeclaration() inout { return null; }
1358 inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
1359 inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
1360 inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
1361 inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
1362 inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
1363 inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
1364 inout(Import) isImport() inout { return null; }
1365 inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
1366 inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
1367 inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
1368 inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
1369 inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
6384eff5 1370 inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
5fee5ec3
IB
1371 inout(OverloadSet) isOverloadSet() inout { return null; }
1372 inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
6384eff5 1373 inout(StaticAssert) isStaticAssert() inout { return null; }
5fee5ec3
IB
1374}
1375
1376/***********************************************************
1377 * Dsymbol that generates a scope
1378 */
1379extern (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
1385private:
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
1393public:
31350635 1394 final extern (D) this() nothrow
5fee5ec3
IB
1395 {
1396 }
1397
31350635 1398 final extern (D) this(Identifier ident) nothrow
5fee5ec3
IB
1399 {
1400 super(ident);
1401 }
1402
31350635 1403 final extern (D) this(const ref Loc loc, Identifier ident) nothrow
5fee5ec3
IB
1404 {
1405 super(loc, ident);
1406 }
1407
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;
c8dfa79c
IB
1547
1548 /* If two imports from C import files, pick first one, as C has global name space
1549 */
1550 if (s.isCsymbol() && s2.isCsymbol())
1551 continue;
1552
5fee5ec3
IB
1553 if (!(flags & IgnoreErrors))
1554 ScopeDsymbol.multiplyDefined(loc, s, s2);
1555 break;
1556 }
1557 }
1558 }
1559 }
1560 if (s)
1561 {
1562 /* Build special symbol if we had multiple finds
1563 */
1564 if (a)
1565 {
1566 if (!s.isOverloadSet())
1567 a = mergeOverloadSet(ident, a, s);
1568 s = a;
1569 }
1570 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1571 return s;
1572 }
1573 //printf(" not found in imports\n");
1574 return null;
1575 }
1576
1577 extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1578 {
1579 if (!os)
1580 {
1581 os = new OverloadSet(ident);
1582 os.parent = this;
1583 }
1584 if (OverloadSet os2 = s.isOverloadSet())
1585 {
1586 // Merge the cross-module overload set 'os2' into 'os'
1587 if (os.a.dim == 0)
1588 {
1589 os.a.setDim(os2.a.dim);
1590 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1591 }
1592 else
1593 {
1594 for (size_t i = 0; i < os2.a.dim; i++)
1595 {
1596 os = mergeOverloadSet(ident, os, os2.a[i]);
1597 }
1598 }
1599 }
1600 else
1601 {
1602 assert(s.isOverloadable());
1603 /* Don't add to os[] if s is alias of previous sym
1604 */
1605 for (size_t j = 0; j < os.a.dim; j++)
1606 {
1607 Dsymbol s2 = os.a[j];
1608 if (s.toAlias() == s2.toAlias())
1609 {
1610 if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
1611 {
1612 os.a[j] = s;
1613 }
1614 goto Lcontinue;
1615 }
1616 }
1617 os.push(s);
1618 Lcontinue:
1619 }
1620 return os;
1621 }
1622
31350635 1623 void importScope(Dsymbol s, Visibility visibility) nothrow
5fee5ec3
IB
1624 {
1625 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1626 // No circular or redundant import's
1627 if (s != this)
1628 {
1629 if (!importedScopes)
1630 importedScopes = new Dsymbols();
1631 else
1632 {
1633 for (size_t i = 0; i < importedScopes.dim; i++)
1634 {
1635 Dsymbol ss = (*importedScopes)[i];
1636 if (ss == s) // if already imported
1637 {
1638 if (visibility.kind > visibilities[i])
1639 visibilities[i] = visibility.kind; // upgrade access
1640 return;
1641 }
1642 }
1643 }
1644 importedScopes.push(s);
1645 visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.dim * (visibilities[0]).sizeof);
1646 visibilities[importedScopes.dim - 1] = visibility.kind;
1647 }
1648 }
1649
5eb9927a
IB
1650
1651 /*****************************************
1652 * Returns: the symbols whose members have been imported, i.e. imported modules
1653 * and template mixins.
1654 *
1655 * See_Also: importScope
1656 */
1657 extern (D) final Dsymbols* getImportedScopes() nothrow @nogc @safe pure
1658 {
1659 return importedScopes;
1660 }
1661
1662 /*****************************************
1663 * Returns: the array of visibilities associated with each imported scope. The
1664 * length of the array matches the imported scopes array.
1665 *
1666 * See_Also: getImportedScopes
1667 */
1668 extern (D) final Visibility.Kind[] getImportVisibilities() nothrow @nogc @safe pure
1669 {
1670 if (!importedScopes)
1671 return null;
1672
1673 return (() @trusted => visibilities[0 .. importedScopes.dim])();
1674 }
1675
31350635 1676 extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
5fee5ec3
IB
1677 {
1678 auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1679 if (pary.length <= p.tag)
1680 pary.length = p.tag + 1;
1681 (*pary)[p.tag] = true;
1682 }
1683
31350635 1684 bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
5fee5ec3
IB
1685 {
1686 if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1687 visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1688 return true;
1689 foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1690 {
1691 // only search visible scopes && imported modules should ignore private imports
1692 if (visibility.kind <= visibilities[i] &&
1693 ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
1694 return true;
1695 }
1696 return false;
1697 }
1698
31350635 1699 override final bool isforwardRef() nothrow
5fee5ec3
IB
1700 {
1701 return (members is null);
1702 }
1703
1704 static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1705 {
1706 version (none)
1707 {
1708 printf("ScopeDsymbol::multiplyDefined()\n");
1709 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1710 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1711 }
1712 if (loc.isValid())
1713 {
1714 .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
1715 s1.kind(), s1.toPrettyChars(), s1.locToChars(),
1716 s2.kind(), s2.toPrettyChars(), s2.locToChars());
1717
1718 static if (0)
1719 {
1720 if (auto so = s1.isOverloadSet())
1721 {
1722 printf("first %p:\n", so);
1723 foreach (s; so.a[])
1724 {
1725 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1726 }
1727 }
1728 if (auto so = s2.isOverloadSet())
1729 {
1730 printf("second %p:\n", so);
1731 foreach (s; so.a[])
1732 {
1733 printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1734 }
1735 }
1736 }
1737 }
1738 else
1739 {
1740 s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1741 }
1742 }
1743
1744 override const(char)* kind() const
1745 {
1746 return "ScopeDsymbol";
1747 }
1748
1749 /*******************************************
1750 * Look for member of the form:
1751 * const(MemberInfo)[] getMembers(string);
1752 * Returns NULL if not found
1753 */
1754 final FuncDeclaration findGetMembers()
1755 {
1756 Dsymbol s = search_function(this, Id.getmembers);
1757 FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1758 version (none)
1759 {
1760 // Finish
1761 __gshared TypeFunction tfgetmembers;
1762 if (!tfgetmembers)
1763 {
1764 Scope sc;
1765 auto parameters = new Parameters();
1766 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1767 parameters.push(p);
1768 Type tret = null;
1769 tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1770 tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1771 }
1772 if (fdx)
1773 fdx = fdx.overloadExactMatch(tfgetmembers);
1774 }
1775 if (fdx && fdx.isVirtual())
1776 fdx = null;
1777 return fdx;
1778 }
1779
1780 /********************************
1781 * Insert Dsymbol in table.
1782 * Params:
1783 * s = symbol to add
1784 * Returns:
1785 * null if already in table, `s` if inserted
1786 */
31350635 1787 Dsymbol symtabInsert(Dsymbol s) nothrow
5fee5ec3
IB
1788 {
1789 return symtab.insert(s);
1790 }
1791
1792 /****************************************
1793 * Look up identifier in symbol table.
1794 * Params:
1795 * s = symbol
1796 * id = identifier to look up
1797 * Returns:
1798 * Dsymbol if found, null if not
1799 */
31350635 1800 Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
5fee5ec3
IB
1801 {
1802 return symtab.lookup(id);
1803 }
1804
1805 /****************************************
1806 * Return true if any of the members are static ctors or static dtors, or if
1807 * any members have members that are.
1808 */
1809 override bool hasStaticCtorOrDtor()
1810 {
1811 if (members)
1812 {
1813 for (size_t i = 0; i < members.dim; i++)
1814 {
1815 Dsymbol member = (*members)[i];
1816 if (member.hasStaticCtorOrDtor())
1817 return true;
1818 }
1819 }
1820 return false;
1821 }
1822
1823 extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1824
1825 /***************************************
1826 * Expands attribute declarations in members in depth first
1827 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1828 * member.
1829 * If dg returns !=0, stops and returns that value else returns 0.
1830 * Use this function to avoid the O(N + N^2/2) complexity of
1831 * calculating dim and calling N times getNth.
1832 * Returns:
1833 * last value returned by dg()
1834 */
1835 extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1836 {
1837 assert(dg);
1838 if (!members)
1839 return 0;
1840 size_t n = pn ? *pn : 0; // take over index
1841 int result = 0;
1842 foreach (size_t i; 0 .. members.dim)
1843 {
1844 Dsymbol s = (*members)[i];
1845 if (AttribDeclaration a = s.isAttribDeclaration())
1846 result = _foreach(sc, a.include(sc), dg, &n);
1847 else if (TemplateMixin tm = s.isTemplateMixin())
1848 result = _foreach(sc, tm.members, dg, &n);
1849 else if (s.isTemplateInstance())
1850 {
1851 }
1852 else if (s.isUnitTestDeclaration())
1853 {
1854 }
1855 else
1856 result = dg(n++, s);
1857 if (result)
1858 break;
1859 }
1860 if (pn)
1861 *pn = n; // update index
1862 return result;
1863 }
1864
1865 override final inout(ScopeDsymbol) isScopeDsymbol() inout
1866 {
1867 return this;
1868 }
1869
1870 override void accept(Visitor v)
1871 {
1872 v.visit(this);
1873 }
1874}
1875
1876/***********************************************************
1877 * With statement scope
1878 */
1879extern (C++) final class WithScopeSymbol : ScopeDsymbol
1880{
1881 WithStatement withstate;
1882
31350635 1883 extern (D) this(WithStatement withstate) nothrow
5fee5ec3
IB
1884 {
1885 this.withstate = withstate;
1886 }
1887
1888 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1889 {
1890 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1891 if (flags & SearchImportsOnly)
1892 return null;
1893 // Acts as proxy to the with class declaration
1894 Dsymbol s = null;
1895 Expression eold = null;
fd43568c 1896 for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
5fee5ec3 1897 {
9c7d5e88 1898 if (e.op == EXP.scope_)
5fee5ec3
IB
1899 {
1900 s = (cast(ScopeExp)e).sds;
1901 }
9c7d5e88 1902 else if (e.op == EXP.type)
5fee5ec3
IB
1903 {
1904 s = e.type.toDsymbol(null);
1905 }
1906 else
1907 {
1908 Type t = e.type.toBasetype();
1909 s = t.toDsymbol(null);
1910 }
1911 if (s)
1912 {
1913 s = s.search(loc, ident, flags);
1914 if (s)
1915 return s;
1916 }
1917 eold = e;
1918 }
1919 return null;
1920 }
1921
1922 override inout(WithScopeSymbol) isWithScopeSymbol() inout
1923 {
1924 return this;
1925 }
1926
1927 override void accept(Visitor v)
1928 {
1929 v.visit(this);
1930 }
1931}
1932
1933/***********************************************************
1934 * Array Index/Slice scope
1935 */
1936extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1937{
1938 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
9c7d5e88 1939 // Discriminated using DYNCAST and, for expressions, also EXP
5fee5ec3
IB
1940 private RootObject arrayContent;
1941 Scope* sc;
1942
31350635 1943 extern (D) this(Scope* sc, Expression exp) nothrow
5fee5ec3
IB
1944 {
1945 super(exp.loc, null);
9c7d5e88 1946 assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
5fee5ec3
IB
1947 this.sc = sc;
1948 this.arrayContent = exp;
1949 }
1950
31350635 1951 extern (D) this(Scope* sc, TypeTuple type) nothrow
5fee5ec3
IB
1952 {
1953 this.sc = sc;
1954 this.arrayContent = type;
1955 }
1956
31350635 1957 extern (D) this(Scope* sc, TupleDeclaration td) nothrow
5fee5ec3
IB
1958 {
1959 this.sc = sc;
1960 this.arrayContent = td;
1961 }
1962
1963 /// This override is used to solve `$`
1964 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
1965 {
1966 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1967 if (ident != Id.dollar)
1968 return null;
1969
1970 VarDeclaration* pvar;
1971 Expression ce;
1972
1973 static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
1974 {
1975
1976 /* $ gives the number of type entries in the type tuple
1977 */
1978 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1979 Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
1980 v._init = new ExpInitializer(Loc.initial, e);
1981 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1982 v.dsymbolSemantic(sc);
1983 return v;
1984 }
1985
1986 const DYNCAST kind = arrayContent.dyncast();
610d7898 1987 switch (kind) with (DYNCAST)
5fee5ec3 1988 {
610d7898 1989 case dsymbol:
5fee5ec3
IB
1990 TupleDeclaration td = cast(TupleDeclaration) arrayContent;
1991 /* $ gives the number of elements in the tuple
1992 */
1993 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1994 Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
1995 v._init = new ExpInitializer(Loc.initial, e);
1996 v.storage_class |= STC.temp | STC.static_ | STC.const_;
1997 v.dsymbolSemantic(sc);
1998 return v;
610d7898 1999 case type:
5fee5ec3 2000 return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
610d7898
IB
2001 default:
2002 break;
5fee5ec3
IB
2003 }
2004 Expression exp = cast(Expression) arrayContent;
2005 if (auto ie = exp.isIndexExp())
2006 {
2007 /* array[index] where index is some function of $
2008 */
2009 pvar = &ie.lengthVar;
2010 ce = ie.e1;
2011 }
2012 else if (auto se = exp.isSliceExp())
2013 {
2014 /* array[lwr .. upr] where lwr or upr is some function of $
2015 */
2016 pvar = &se.lengthVar;
2017 ce = se.e1;
2018 }
2019 else if (auto ae = exp.isArrayExp())
2020 {
2021 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
2022 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
2023 */
2024 pvar = &ae.lengthVar;
2025 ce = ae.e1;
2026 }
2027 else
2028 {
2029 /* Didn't find $, look in enclosing scope(s).
2030 */
2031 return null;
2032 }
2033 ce = ce.lastComma();
2034 /* If we are indexing into an array that is really a type
2035 * tuple, rewrite this as an index into a type tuple and
2036 * try again.
2037 */
2038 if (auto te = ce.isTypeExp())
2039 {
2040 if (auto ttp = te.type.isTypeTuple())
2041 return dollarFromTypeTuple(loc, ttp, sc);
2042 }
2043 /* *pvar is lazily initialized, so if we refer to $
2044 * multiple times, it gets set only once.
2045 */
2046 if (!*pvar) // if not already initialized
2047 {
2048 /* Create variable v and set it to the value of $
2049 */
2050 VarDeclaration v;
2051 Type t;
2052 if (auto tupexp = ce.isTupleExp())
2053 {
2054 /* It is for an expression tuple, so the
2055 * length will be a const.
2056 */
2057 Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
2058 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
2059 v.storage_class |= STC.temp | STC.static_ | STC.const_;
2060 }
2061 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
2062 {
2063 // Look for opDollar
9c7d5e88 2064 assert(exp.op == EXP.array || exp.op == EXP.slice);
5fee5ec3
IB
2065 AggregateDeclaration ad = isAggregate(t);
2066 assert(ad);
2067 Dsymbol s = ad.search(loc, Id.opDollar);
2068 if (!s) // no dollar exists -- search in higher scope
2069 return null;
2070 s = s.toAlias();
2071 Expression e = null;
2072 // Check for multi-dimensional opDollar(dim) template.
2073 if (TemplateDeclaration td = s.isTemplateDeclaration())
2074 {
2075 dinteger_t dim = 0;
9c7d5e88 2076 if (exp.op == EXP.array)
5fee5ec3
IB
2077 {
2078 dim = (cast(ArrayExp)exp).currentDimension;
2079 }
9c7d5e88 2080 else if (exp.op == EXP.slice)
5fee5ec3
IB
2081 {
2082 dim = 0; // slices are currently always one-dimensional
2083 }
2084 else
2085 {
2086 assert(0);
2087 }
2088 auto tiargs = new Objects();
2089 Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
2090 edim = edim.expressionSemantic(sc);
2091 tiargs.push(edim);
2092 e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
2093 }
2094 else
2095 {
2096 /* opDollar exists, but it's not a template.
2097 * This is acceptable ONLY for single-dimension indexing.
2098 * Note that it's impossible to have both template & function opDollar,
2099 * because both take no arguments.
2100 */
9c7d5e88 2101 if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1)
5fee5ec3
IB
2102 {
2103 exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
2104 return null;
2105 }
2106 Declaration d = s.isDeclaration();
2107 assert(d);
2108 e = new DotVarExp(loc, ce, d);
2109 }
2110 e = e.expressionSemantic(sc);
2111 if (!e.type)
2112 exp.error("`%s` has no value", e.toChars());
2113 t = e.type.toBasetype();
2114 if (t && t.ty == Tfunction)
2115 e = new CallExp(e.loc, e);
2116 v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
2117 v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
2118 }
2119 else
2120 {
2121 /* For arrays, $ will either be a compile-time constant
2122 * (in which case its value in set during constant-folding),
2123 * or a variable (in which case an expression is created in
2124 * toir.c).
2125 */
2126 auto e = new VoidInitializer(Loc.initial);
2127 e.type = Type.tsize_t;
2128 v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
2129 v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
2130 }
2131 *pvar = v;
2132 }
2133 (*pvar).dsymbolSemantic(sc);
2134 return (*pvar);
2135 }
2136
2137 override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
2138 {
2139 return this;
2140 }
2141
2142 override void accept(Visitor v)
2143 {
2144 v.visit(this);
2145 }
2146}
2147
2148/***********************************************************
2149 * Overload Sets
2150 */
2151extern (C++) final class OverloadSet : Dsymbol
2152{
2153 Dsymbols a; // array of Dsymbols
2154
31350635 2155 extern (D) this(Identifier ident, OverloadSet os = null) nothrow
5fee5ec3
IB
2156 {
2157 super(ident);
2158 if (os)
2159 {
2160 a.pushSlice(os.a[]);
2161 }
2162 }
2163
31350635 2164 void push(Dsymbol s) nothrow
5fee5ec3
IB
2165 {
2166 a.push(s);
2167 }
2168
2169 override inout(OverloadSet) isOverloadSet() inout
2170 {
2171 return this;
2172 }
2173
2174 override const(char)* kind() const
2175 {
2176 return "overloadset";
2177 }
2178
2179 override void accept(Visitor v)
2180 {
2181 v.visit(this);
2182 }
2183}
2184
2185/***********************************************************
2186 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2187 * ForwardingScopeDeclaration to forward symbol insertions to another
2188 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2189 * details.
2190 */
2191extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
2192{
ec486b73 2193 extern (D) this() nothrow
5fee5ec3 2194 {
ec486b73 2195 super();
5fee5ec3 2196 }
31350635
IB
2197
2198 override Dsymbol symtabInsert(Dsymbol s) nothrow
5fee5ec3 2199 {
5fee5ec3
IB
2200 if (auto d = s.isDeclaration())
2201 {
2202 if (d.storage_class & STC.local)
2203 {
2204 // Symbols with storage class STC.local are not
2205 // forwarded, but stored in the local symbol
2206 // table. (Those are the `static foreach` variables.)
2207 if (!symtab)
2208 {
2209 symtab = new DsymbolTable();
2210 }
2211 return super.symtabInsert(s); // insert locally
2212 }
2213 }
ec486b73
IB
2214 auto forward = parent.isScopeDsymbol();
2215 assert(forward);
5fee5ec3
IB
2216 if (!forward.symtab)
2217 {
2218 forward.symtab = new DsymbolTable();
2219 }
2220 // Non-STC.local symbols are forwarded to `forward`.
2221 return forward.symtabInsert(s);
2222 }
2223
2224 /************************
2225 * This override handles the following two cases:
2226 * static foreach (i, i; [0]) { ... }
2227 * and
2228 * static foreach (i; [0]) { enum i = 2; }
2229 */
31350635 2230 override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
5fee5ec3 2231 {
5fee5ec3
IB
2232 // correctly diagnose clashing foreach loop variables.
2233 if (auto d = s.isDeclaration())
2234 {
2235 if (d.storage_class & STC.local)
2236 {
2237 if (!symtab)
2238 {
2239 symtab = new DsymbolTable();
2240 }
2241 return super.symtabLookup(s,id);
2242 }
2243 }
2244 // Declarations within `static foreach` do not clash with
2245 // `static foreach` loop variables.
ec486b73
IB
2246 auto forward = parent.isScopeDsymbol();
2247 assert(forward);
5fee5ec3
IB
2248 if (!forward.symtab)
2249 {
2250 forward.symtab = new DsymbolTable();
2251 }
2252 return forward.symtabLookup(s,id);
2253 }
2254
2255 override void importScope(Dsymbol s, Visibility visibility)
2256 {
ec486b73
IB
2257 auto forward = parent.isScopeDsymbol();
2258 assert(forward);
5fee5ec3
IB
2259 forward.importScope(s, visibility);
2260 }
2261
2262 override const(char)* kind()const{ return "local scope"; }
2263
31350635 2264 override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
5fee5ec3
IB
2265 {
2266 return this;
2267 }
2268
2269}
2270
2271/**
2272 * Class that holds an expression in a Dsymbol wrapper.
2273 * This is not an AST node, but a class used to pass
2274 * an expression as a function parameter of type Dsymbol.
2275 */
2276extern (C++) final class ExpressionDsymbol : Dsymbol
2277{
2278 Expression exp;
31350635 2279 this(Expression exp) nothrow
5fee5ec3
IB
2280 {
2281 super();
2282 this.exp = exp;
2283 }
2284
31350635 2285 override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
5fee5ec3
IB
2286 {
2287 return this;
2288 }
2289}
2290
2291/**********************************************
2292 * Encapsulate assigning to an alias:
2293 * `identifier = type;`
2294 * `identifier = symbol;`
2295 * where `identifier` is an AliasDeclaration in scope.
2296 */
2297extern (C++) final class AliasAssign : Dsymbol
2298{
2299 Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
2300 Type type; /// replace previous RHS of AliasDeclaration with `type`
2301 Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
2302 /// only one of type and aliassym can be != null
2303
31350635 2304 extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
5fee5ec3
IB
2305 {
2306 super(loc, null);
2307 this.ident = ident;
2308 this.type = type;
2309 this.aliassym = aliassym;
2310 }
2311
2312 override AliasAssign syntaxCopy(Dsymbol s)
2313 {
2314 assert(!s);
2315 AliasAssign aa = new AliasAssign(loc, ident,
2316 type ? type.syntaxCopy() : null,
2317 aliassym ? aliassym.syntaxCopy(null) : null);
2318 return aa;
2319 }
2320
2321 override inout(AliasAssign) isAliasAssign() inout
2322 {
2323 return this;
2324 }
2325
2326 override const(char)* kind() const
2327 {
2328 return "alias assignment";
2329 }
2330
2331 override void accept(Visitor v)
2332 {
2333 v.visit(this);
2334 }
2335}
2336
2337/***********************************************************
2338 * Table of Dsymbol's
2339 */
2340extern (C++) final class DsymbolTable : RootObject
2341{
2342 AssocArray!(Identifier, Dsymbol) tab;
2343
31350635
IB
2344 nothrow:
2345
5fee5ec3
IB
2346 /***************************
2347 * Look up Identifier in symbol table
2348 * Params:
2349 * ident = identifer to look up
2350 * Returns:
2351 * Dsymbol if found, null if not
2352 */
2353 Dsymbol lookup(const Identifier ident)
2354 {
2355 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2356 return tab[ident];
2357 }
2358
2359 /**********
2360 * Replace existing symbol in symbol table with `s`.
2361 * If it's not there, add it.
2362 * Params:
2363 * s = replacement symbol with same identifier
2364 */
2365 void update(Dsymbol s)
2366 {
2367 *tab.getLvalue(s.ident) = s;
2368 }
2369
2370 /**************************
2371 * Insert Dsymbol in table.
2372 * Params:
2373 * s = symbol to add
2374 * Returns:
2375 * null if already in table, `s` if inserted
2376 */
2377 Dsymbol insert(Dsymbol s)
2378 {
2379 return insert(s.ident, s);
2380 }
2381
2382 /**************************
2383 * Insert Dsymbol in table.
2384 * Params:
2385 * ident = identifier to serve as index
2386 * s = symbol to add
2387 * Returns:
2388 * null if already in table, `s` if inserted
2389 */
2390 Dsymbol insert(const Identifier ident, Dsymbol s)
2391 {
2392 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2393 Dsymbol* ps = tab.getLvalue(ident);
2394 if (*ps)
2395 return null; // already in table
2396 *ps = s;
2397 return s;
2398 }
2399
2400 /*****************
2401 * Returns:
2402 * number of symbols in symbol table
2403 */
2404 size_t length() const pure
2405 {
2406 return tab.length;
2407 }
2408}
2409
2410/**********************************************
2411 * ImportC tag symbols sit in a parallel symbol table,
2412 * so that this C code works:
2413 * ---
2414 * struct S { a; };
2415 * int S;
2416 * struct S s;
2417 * ---
2418 * But there are relatively few such tag symbols, so that would be
2419 * a waste of memory and complexity. An additional problem is we'd like the D side
2420 * to find the tag symbols with ordinary lookup, not lookup in both
2421 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2422 * The solution is to put the tag symbols that conflict into an associative
2423 * array, indexed by the address of the ordinary symbol that conflicts with it.
2424 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2425 * A side effect of our approach is that D code cannot access a tag symbol that is
2426 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2427 * has mentioned it when importing C headers. If someone wants to do it,
2428 * too bad so sad. Change the C code.
2429 * This function fixes up the symbol table when faced with adding a new symbol
2430 * `s` when there is an existing symbol `s2` with the same name.
2431 * C also allows forward and prototype declarations of tag symbols,
2432 * this function merges those.
2433 * Params:
2434 * sc = context
2435 * s = symbol to add to symbol table
2436 * s2 = existing declaration
2437 * sds = symbol table
2438 * Returns:
2439 * if s and s2 are successfully put in symbol table then return the merged symbol,
2440 * null if they conflict
2441 */
2442Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2443{
2444 enum log = false;
d7569187 2445 if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
235d5a96 2446 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
5fee5ec3
IB
2447 auto sd = s.isScopeDsymbol(); // new declaration
2448 auto sd2 = s2.isScopeDsymbol(); // existing declaration
2449
b6df1132
IB
2450 static if (log) void print(EnumDeclaration sd)
2451 {
2452 printf("members: %p\n", sd.members);
2453 printf("symtab: %p\n", sd.symtab);
2454 printf("endlinnum: %d\n", sd.endlinnum);
2455 printf("type: %s\n", sd.type.toChars());
2456 printf("memtype: %s\n", sd.memtype.toChars());
2457 }
2458
5fee5ec3
IB
2459 if (!sd2)
2460 {
2461 /* Look in tag table
2462 */
2463 if (log) printf(" look in tag table\n");
2464 if (auto p = cast(void*)s2 in sc._module.tagSymTab)
2465 {
2466 Dsymbol s2tag = *p;
2467 sd2 = s2tag.isScopeDsymbol();
2468 assert(sd2); // only tags allowed in tag symbol table
2469 }
2470 }
2471
2472 if (sd && sd2) // `s` is a tag, `sd2` is the same tag
2473 {
2474 if (log) printf(" tag is already defined\n");
2475
2476 if (sd.kind() != sd2.kind()) // being enum/struct/union must match
2477 return null; // conflict
2478
2479 /* Not a redeclaration if one is a forward declaration.
2480 * Move members to the first declared type, which is sd2.
2481 */
2482 if (sd2.members)
2483 {
2484 if (!sd.members)
2485 return sd2; // ignore the sd redeclaration
2486 }
2487 else if (sd.members)
2488 {
2489 sd2.members = sd.members; // transfer definition to sd2
2490 sd.members = null;
b6df1132
IB
2491 if (auto ed2 = sd2.isEnumDeclaration())
2492 {
2493 auto ed = sd.isEnumDeclaration();
2494 if (ed.memtype != ed2.memtype)
2495 return null; // conflict
2496
2497 // transfer ed's members to sd2
2498 ed2.members.foreachDsymbol( (s)
2499 {
2500 if (auto em = s.isEnumMember())
2501 em.ed = ed2;
2502 });
2503
2504 ed2.type = ed.type;
2505 ed2.memtype = ed.memtype;
2506 ed2.added = false;
2507 }
5fee5ec3
IB
2508 return sd2;
2509 }
2510 else
2511 return sd2; // ignore redeclaration
2512 }
2513 else if (sd) // `s` is a tag, `s2` is not
2514 {
2515 if (log) printf(" s is tag, s2 is not\n");
2516 /* add `s` as tag indexed by s2
2517 */
2518 sc._module.tagSymTab[cast(void*)s2] = s;
2519 return s;
2520 }
2521 else if (s2 is sd2) // `s2` is a tag, `s` is not
2522 {
2523 if (log) printf(" s2 is tag, s is not\n");
2524 /* replace `s2` in symbol table with `s`,
2525 * then add `s2` as tag indexed by `s`
2526 */
2527 sds.symtab.update(s);
2528 sc._module.tagSymTab[cast(void*)s] = s2;
2529 return s;
2530 }
235d5a96 2531 // neither s2 nor s is a tag
5fee5ec3
IB
2532 if (log) printf(" collision\n");
2533 return null;
2534}
2535
2536
0fb57034
IB
2537/**********************************************
2538 * ImportC allows redeclarations of C variables, functions and typedefs.
2539 * extern int x;
2540 * int x = 3;
2541 * and:
2542 * extern void f();
2543 * void f() { }
2544 * Attempt to merge them.
2545 * Params:
2546 * sc = context
2547 * s = symbol to add to symbol table
2548 * s2 = existing declaration
2549 * sds = symbol table
2550 * Returns:
2551 * if s and s2 are successfully put in symbol table then return the merged symbol,
2552 * null if they conflict
2553 */
2554Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2555{
2556 enum log = false;
2557 if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
235d5a96 2558 if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
0fb57034
IB
2559
2560 static Dsymbol collision()
2561 {
2562 if (log) printf(" collision\n");
2563 return null;
2564 }
610d7898
IB
2565 /*
2566 Handle merging declarations with asm("foo") and their definitions
2567 */
2568 static void mangleWrangle(Declaration oldDecl, Declaration newDecl)
2569 {
2570 if (oldDecl && newDecl)
2571 {
2572 newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null;
2573 }
2574 }
0fb57034
IB
2575
2576 auto vd = s.isVarDeclaration(); // new declaration
2577 auto vd2 = s2.isVarDeclaration(); // existing declaration
2578 if (vd && vd2)
2579 {
fd43568c
IB
2580 /* if one is `static` and the other isn't, the result is undefined
2581 * behavior, C11 6.2.2.7
2582 */
0fb57034
IB
2583 if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
2584 return collision();
2585
2586 const i1 = vd._init && ! vd._init.isVoidInitializer();
2587 const i2 = vd2._init && !vd2._init.isVoidInitializer();
2588
2589 if (i1 && i2)
2590 return collision(); // can't both have initializers
2591
610d7898
IB
2592 mangleWrangle(vd2, vd);
2593
b3f58f87 2594 if (i1) // vd is the definition
fd43568c 2595 {
ae56e2da 2596 vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it
b3f58f87
IB
2597 sds.symtab.update(vd); // replace vd2 with the definition
2598 return vd;
fd43568c 2599 }
0fb57034
IB
2600
2601 /* BUG: the types should match, which needs semantic() to be run on it
2602 * extern int x;
2603 * int x; // match
2604 * typedef int INT;
2605 * INT x; // match
2606 * long x; // collision
2607 * We incorrectly ignore these collisions
2608 */
2609 return vd2;
2610 }
2611
2612 auto fd = s.isFuncDeclaration(); // new declaration
2613 auto fd2 = s2.isFuncDeclaration(); // existing declaration
2614 if (fd && fd2)
2615 {
fd43568c
IB
2616 /* if one is `static` and the other isn't, the result is undefined
2617 * behavior, C11 6.2.2.7
2618 * However, match what gcc allows:
2619 * static int sun1(); int sun1() { return 0; }
2620 * and:
2621 * static int sun2() { return 0; } int sun2();
2622 * Both produce a static function.
2623 *
2624 * Both of these should fail:
2625 * int sun3(); static int sun3() { return 0; }
2626 * and:
2627 * int sun4() { return 0; } static int sun4();
2628 */
2629 // if adding `static`
2630 if ( fd.storage_class & STC.static_ &&
2631 !(fd2.storage_class & STC.static_))
2632 {
0fb57034 2633 return collision();
fd43568c 2634 }
0fb57034
IB
2635
2636 if (fd.fbody && fd2.fbody)
2637 return collision(); // can't both have bodies
2638
610d7898
IB
2639 mangleWrangle(fd2, fd);
2640
b3f58f87 2641 if (fd.fbody) // fd is the definition
fd43568c 2642 {
235d5a96 2643 if (log) printf(" replace existing with new\n");
b3f58f87 2644 sds.symtab.update(fd); // replace fd2 in symbol table with fd
6384eff5 2645 fd.overnext = fd2;
235d5a96
IB
2646
2647 /* If fd2 is covering a tag symbol, then fd has to cover the same one
2648 */
2649 auto ps = cast(void*)fd2 in sc._module.tagSymTab;
2650 if (ps)
2651 sc._module.tagSymTab[cast(void*)fd] = *ps;
2652
b3f58f87 2653 return fd;
fd43568c 2654 }
0fb57034 2655
6384eff5
IB
2656 /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2657 * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
0fb57034 2658 */
6384eff5
IB
2659 fd2.overloadInsert(fd);
2660
0fb57034
IB
2661 return fd2;
2662 }
2663
2664 auto td = s.isAliasDeclaration(); // new declaration
2665 auto td2 = s2.isAliasDeclaration(); // existing declaration
2666 if (td && td2)
2667 {
2668 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2669 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2670 */
2671 return td2;
2672 }
2673
2674 return collision();
2675}
This page took 0.600845 seconds and 5 git commands to generate.