2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
4 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 http://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
14 import core
.stdc
.stdarg
;
15 import core
.stdc
.stdio
;
16 import core
.stdc
.string
;
17 import core
.stdc
.stdlib
;
21 import dmd
.arraytypes
;
27 import dmd
.declaration
;
34 import dmd
.dsymbolsem
;
37 import dmd
.expression
;
38 import dmd
.expressionsem
;
42 import dmd
.identifier
;
50 import dmd
.root
.rootobject
;
51 import dmd
.root
.speller
;
52 import dmd
.root
.string
;
57 /***************************************
58 * Calls dg(Dsymbol *sym) for each Dsymbol.
59 * If dg returns !=0, stops and returns that value else returns 0.
62 * dg = delegate to call for each Dsymbol
64 * last value returned by dg()
66 * See_Also: $(REF each, dmd, root, array)
68 int foreachDsymbol(Dsymbols
* symbols
, scope int delegate(Dsymbol
) dg
)
73 /* Do not use foreach, as the size of the array may expand during iteration
75 for (size_t i
= 0; i
< symbols
.dim
; ++i
)
77 Dsymbol s
= (*symbols
)[i
];
86 /***************************************
87 * Calls dg(Dsymbol *sym) for each Dsymbol.
90 * dg = delegate to call for each Dsymbol
92 * See_Also: $(REF each, dmd, root, array)
94 void foreachDsymbol(Dsymbols
* symbols
, scope void delegate(Dsymbol
) dg
)
99 /* Do not use foreach, as the size of the array may expand during iteration
101 for (size_t i
= 0; i
< symbols
.dim
; ++i
)
103 Dsymbol s
= (*symbols
)[i
];
114 extern (D
) this(uint old
)
144 this(Visibility
.Kind kind
) pure nothrow @nogc @safe
150 * Checks if `this` is less or more visible than `other`
153 * other = Visibility to compare `this` to.
156 * A value `< 0` if `this` is less visible than `other`,
157 * a value `> 0` if `this` is more visible than `other`,
158 * and `0` if they are at the same level.
159 * Note that `package` visibility with different packages
160 * will also return `0`.
162 int opCmp(const Visibility other
) const pure nothrow @nogc @safe
164 return this.kind
- other
.kind
;
170 assert(Visibility(Visibility
.Kind
.public_
) > Visibility(Visibility
.Kind
.private_
));
171 assert(Visibility(Visibility
.Kind
.private_
) < Visibility(Visibility
.Kind
.protected_
));
172 assert(Visibility(Visibility
.Kind
.package_
) >= Visibility(Visibility
.Kind
.package_
));
176 * Checks if `this` is absolutely identical visibility attribute to `other`
178 bool opEquals(ref const Visibility other
) const
180 if (this.kind
== other
.kind
)
182 if (this.kind
== Visibility
.Kind
.package_
)
183 return this.pkg
== other
.pkg
;
192 init
, // initial state
193 semantic
, // semantic() started
194 semanticdone
, // semantic() done
195 semantic2
, // semantic2() started
196 semantic2done
, // semantic2() done
197 semantic3
, // semantic3() started
198 semantic3done
, // semantic3() done
199 inline
, // inline started
200 inlinedone
, // inline done
201 obj
, // toObjFile() run
207 IgnoreNone
= 0x00, // default
208 IgnorePrivateImports
= 0x01, // don't search private imports
209 IgnoreErrors
= 0x02, // don't give error messages
210 IgnoreAmbiguous
= 0x04, // return NULL if ambiguous
211 SearchLocalsOnly
= 0x08, // only look at locals (don't search imports)
212 SearchImportsOnly
= 0x10, // only look in imports
213 SearchUnqualifiedModule
= 0x20, // the module scope search is unqualified,
214 // meaning don't search imports in that scope,
215 // because qualified module searches search
217 IgnoreSymbolVisibility
= 0x80, // also find private and package protected symbols
218 TagNameSpace
= 0x100, // search ImportC tag symbol table
221 /***********************************************************
222 * Struct/Class/Union field state.
223 * Used for transitory information when setting field offsets, such
228 uint offset
; /// byte offset for next field
230 uint fieldOffset
; /// byte offset for the start of the bit field
231 uint fieldSize
; /// byte size of field
232 uint fieldAlign
; /// byte alignment of field
233 uint bitOffset
; /// bit offset for field
235 bool inFlight
; /// bit field is in flight
238 /***********************************************************
240 extern (C
++) class Dsymbol
: ASTNode
244 /// C++ namespace this symbol belongs to
245 CPPNamespaceDeclaration cppnamespace
;
246 Symbol
* csym
; // symbol for code generator
247 Symbol
* isym
; // import version of csym
248 const(char)* comment
; // documentation comment for this Dsymbol
249 const Loc loc
; // where defined
250 Scope
* _scope
; // !=null means context to use for semantic()
251 const(char)* prettystring
; // cached value of toPrettyChars()
252 bool errors
; // this symbol failed to pass semantic()
253 PASS semanticRun
= PASS
.init
;
254 ushort localNum
; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
256 DeprecatedDeclaration depdecl
; // customized deprecation message
257 UserAttributeDeclaration userAttribDecl
; // user defined attributes
259 // !=null means there's a ddoc unittest associated with this symbol
260 // (only use this with ddoc)
261 UnitTestDeclaration ddocUnittest
;
263 final extern (D
) this()
265 //printf("Dsymbol::Dsymbol(%p)\n", this);
266 loc
= Loc(null, 0, 0);
269 final extern (D
) this(Identifier ident
)
271 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
272 this.loc
= Loc(null, 0, 0);
276 final extern (D
) this(const ref Loc loc
, Identifier ident
)
278 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
283 static Dsymbol
create(Identifier ident
)
285 return new Dsymbol(ident
);
288 override const(char)* toChars() const
290 return ident ? ident
.toChars() : "__anonymous";
293 // helper to print fully qualified (template) arguments
294 const(char)* toPrettyCharsHelper()
299 final const(Loc
) getLoc()
301 if (!loc
.isValid()) // avoid bug 5861.
302 if (const m
= getModule())
303 return Loc(m
.srcfile
.toChars(), 0, 0);
307 final const(char)* locToChars()
309 return getLoc().toChars();
312 override bool equals(const RootObject o
) const
316 if (o
.dyncast() != DYNCAST
.dsymbol
)
318 auto s
= cast(Dsymbol
)o
;
319 // Overload sets don't have an ident
320 // Function-local declarations may have identical names
321 // if they are declared in different scopes
322 if (s
&& ident
&& s
.ident
&& ident
.equals(s
.ident
) && localNum
== s
.localNum
)
327 final bool isAnonymous() const
329 return ident
is null || ident
.isAnonymous
;
332 extern(D
) private const(char)[] prettyFormatHelper()
334 const cstr
= toPrettyChars();
335 return '`' ~ cstr
.toDString() ~ "`\0";
338 static if (__VERSION__
< 2092)
340 final void error(const ref Loc loc
, const(char)* format
, ...)
343 va_start(ap
, format
);
344 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
348 final void error(const(char)* format
, ...)
351 va_start(ap
, format
);
352 const loc
= getLoc();
353 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
357 final void deprecation(const ref Loc loc
, const(char)* format
, ...)
360 va_start(ap
, format
);
361 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
365 final void deprecation(const(char)* format
, ...)
368 va_start(ap
, format
);
369 const loc
= getLoc();
370 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
376 pragma(printf
) final void error(const ref Loc loc
, const(char)* format
, ...)
379 va_start(ap
, format
);
380 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
384 pragma(printf
) final void error(const(char)* format
, ...)
387 va_start(ap
, format
);
388 const loc
= getLoc();
389 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
393 pragma(printf
) final void deprecation(const ref Loc loc
, const(char)* format
, ...)
396 va_start(ap
, format
);
397 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
401 pragma(printf
) final void deprecation(const(char)* format
, ...)
404 va_start(ap
, format
);
405 const loc
= getLoc();
406 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
411 final bool checkDeprecated(const ref Loc loc
, Scope
* sc
)
413 if (global
.params
.useDeprecated
== DiagnosticReporting
.off
)
415 if (!this.isDeprecated())
417 // Don't complain if we're inside a deprecated symbol's scope
418 if (sc
.isDeprecated())
420 // Don't complain if we're inside a template constraint
421 // https://issues.dlang.org/show_bug.cgi?id=21831
422 if (sc
.flags
& SCOPE
.constraint
)
425 const(char)* message
= null;
426 for (Dsymbol p
= this; p
; p
= p
.parent
)
428 message
= p
.depdecl ? p
.depdecl
.getMessage() : null;
433 deprecation(loc
, "is deprecated - %s", message
);
435 deprecation(loc
, "is deprecated");
437 if (auto ti
= sc
.parent ? sc
.parent
.isInstantiated() : null)
438 ti
.printInstantiationTrace(Classification
.deprecation
);
439 else if (auto ti
= sc
.parent ? sc
.parent
.isTemplateInstance() : null)
440 ti
.printInstantiationTrace(Classification
.deprecation
);
445 /**********************************
446 * Determine which Module a Dsymbol is in.
448 final Module
getModule()
450 //printf("Dsymbol::getModule()\n");
451 if (TemplateInstance ti
= isInstantiated())
452 return ti
.tempdecl
.getModule();
456 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
457 Module m
= s
.isModule();
465 /**********************************
466 * Determine which Module a Dsymbol is in, as far as access rights go.
468 final Module
getAccessModule()
470 //printf("Dsymbol::getAccessModule()\n");
471 if (TemplateInstance ti
= isInstantiated())
472 return ti
.tempdecl
.getAccessModule();
476 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
477 Module m
= s
.isModule();
480 TemplateInstance ti
= s
.isTemplateInstance();
481 if (ti
&& ti
.enclosing
)
483 /* Because of local template instantiation, the parent isn't where the access
484 * rights come from - it's the template declaration
495 * `pastMixin` returns the enclosing symbol if this is a template mixin.
497 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
500 * See also `parent`, `toParent` and `toParent2`.
502 final inout(Dsymbol
) pastMixin() inout
504 //printf("Dsymbol::pastMixin() %s\n", toChars());
505 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
509 return parent
.pastMixin();
512 /**********************************
513 * `parent` field returns a lexically enclosing scope symbol this is a member of.
515 * `toParent()` returns a logically enclosing scope symbol this is a member of.
516 * It skips over TemplateMixin's.
518 * `toParent2()` returns an enclosing scope symbol this is living at runtime.
519 * It skips over both TemplateInstance's and TemplateMixin's.
520 * It's used when looking for the 'this' pointer of the enclosing function/class.
522 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
523 * instead of the instantiation scope.
525 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
526 * if a template declaration is non-local i.e. global or static.
531 * template Foo(alias a) { mixin Bar!(); }
532 * mixin template Bar() {
533 * public { // VisibilityDeclaration
534 * void baz() { a = 2; }
539 * alias foo = Foo!(v);
544 * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
545 * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
546 * // s.toParent() == TemplateInstance('mod.test.Foo!()')
547 * // s.toParent2() == FuncDeclaration('mod.test')
548 * // s.toParentDecl() == Module('mod')
549 * // s.toParentLocal() == FuncDeclaration('mod.test')
552 final inout(Dsymbol
) toParent() inout
554 return parent ? parent
.pastMixin() : null;
558 final inout(Dsymbol
) toParent2() inout
560 if (!parent ||
!parent
.isTemplateInstance
&& !parent
.isForwardingAttribDeclaration() && !parent
.isForwardingScopeDsymbol())
562 return parent
.toParent2
;
566 final inout(Dsymbol
) toParentDecl() inout
568 return toParentDeclImpl(false);
572 final inout(Dsymbol
) toParentLocal() inout
574 return toParentDeclImpl(true);
577 private inout(Dsymbol
) toParentDeclImpl(bool localOnly
) inout
580 if (!p ||
!p
.isTemplateInstance())
582 auto ti
= p
.isTemplateInstance();
583 if (ti
.tempdecl
&& (!localOnly ||
!(cast(TemplateDeclaration
)ti
.tempdecl
).isstatic
))
584 return ti
.tempdecl
.toParentDeclImpl(localOnly
);
585 return parent
.toParentDeclImpl(localOnly
);
589 * Returns the declaration scope scope of `this` unless any of the symbols
590 * `p1` or `p2` resides in its enclosing instantiation scope then the
591 * latter is returned.
593 final Dsymbol
toParentP(Dsymbol p1
, Dsymbol p2
= null)
595 return followInstantiationContext(p1
, p2
) ?
toParent2() : toParentLocal();
598 final inout(TemplateInstance
) isInstantiated() inout
602 auto ti
= parent
.isTemplateInstance();
603 if (ti
&& !ti
.isTemplateMixin())
605 return parent
.isInstantiated();
609 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
610 * instantiation scope of `this`.
612 final bool followInstantiationContext(Dsymbol p1
, Dsymbol p2
= null)
614 static bool has2This(Dsymbol s
)
616 if (auto f
= s
.isFuncDeclaration())
618 if (auto ad
= s
.isAggregateDeclaration())
619 return ad
.vthis2
!is null;
626 auto outer
= toParent();
629 auto ti
= outer
.isTemplateInstance();
632 foreach (oarg
; *ti
.tiargs
)
634 auto sa
= getDsymbol(oarg
);
637 sa
= sa
.toAlias().toParent2();
642 else if (p2
&& sa
== p2
)
645 outer
= ti
.tempdecl
.toParent();
652 // Check if this function is a member of a template which has only been
653 // instantiated speculatively, eg from inside is(typeof()).
654 // Return the speculative template instance it is part of,
655 // or NULL if not speculative.
656 final inout(TemplateInstance
) isSpeculative() inout
660 auto ti
= parent
.isTemplateInstance();
663 if (!parent
.toParent())
665 return parent
.isSpeculative();
668 final Ungag
ungagSpeculative() const
670 uint oldgag
= global
.gag
;
671 if (global
.gag
&& !isSpeculative() && !toParent2().isFuncDeclaration())
673 return Ungag(oldgag
);
676 // kludge for template.isSymbol()
677 override final DYNCAST
dyncast() const
679 return DYNCAST
.dsymbol
;
682 /*************************************
683 * Do syntax copy of an array of Dsymbol's.
685 extern (D
) static Dsymbols
* arraySyntaxCopy(Dsymbols
* a
)
691 for (size_t i
= 0; i
< b
.dim
; i
++)
693 (*b
)[i
] = (*b
)[i
].syntaxCopy(null);
699 Identifier
getIdent()
704 const(char)* toPrettyChars(bool QualifyTypes
= false)
706 if (prettystring
&& !QualifyTypes
)
709 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
718 // Computer number of components
719 size_t complength
= 0;
720 for (Dsymbol p
= this; p
; p
= p
.parent
)
723 // Allocate temporary array comp[]
724 alias T
= const(char)[];
725 auto compptr
= cast(T
*)Mem
.check(malloc(complength
* T
.sizeof
));
726 auto comp
= compptr
[0 .. complength
];
728 // Fill in comp[] and compute length of final result
731 for (Dsymbol p
= this; p
; p
= p
.parent
)
733 const s
= QualifyTypes ? p
.toPrettyCharsHelper() : p
.toChars();
734 const len
= strlen(s
);
735 comp
[i
] = s
[0 .. len
];
740 auto s
= cast(char*)mem
.xmalloc_noscan(length
);
741 auto q
= s
+ length
- 1;
743 foreach (j
; 0 .. complength
)
745 const t
= comp
[j
].ptr
;
746 const len
= comp
[j
].length
;
759 const(char)* kind() const pure nothrow @nogc @safe
764 /*********************************
765 * If this symbol is really an alias for another,
767 * If needed, semantic() is invoked due to resolve forward reference.
774 /*********************************
775 * Resolve recursive tuple expansion in eponymous template.
782 void addMember(Scope
* sc
, ScopeDsymbol sds
)
784 //printf("Dsymbol::addMember('%s')\n", toChars());
785 //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
786 //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
788 if (isAnonymous()) // no name, so can't add it to symbol table
791 if (!sds
.symtabInsert(this)) // if name is already defined
793 if (isAliasDeclaration() && !_scope
)
795 Dsymbol s2
= sds
.symtabLookup(this,ident
);
797 // If using C tag/prototype/forward declaration rules
798 if (sc
.flags
& SCOPE
.Cfile
)
800 if (handleTagSymbols(*sc
, this, s2
, sds
))
802 if (handleSymbolRedeclarations(*sc
, this, s2
, sds
))
805 sds
.multiplyDefined(Loc
.initial
, this, s2
); // ImportC doesn't allow overloading
810 if (!s2
.overloadInsert(this))
812 sds
.multiplyDefined(Loc
.initial
, this, s2
);
816 if (sds
.isAggregateDeclaration() || sds
.isEnumDeclaration())
818 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
820 error("`.%s` property cannot be redefined", ident
.toChars());
826 /*************************************
827 * Set scope for future semantic analysis so we can
828 * deal better with forward references.
830 void setScope(Scope
* sc
)
832 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
834 sc
.setNoFree(); // may need it even after semantic() finishes
837 depdecl
= sc
.depdecl
;
839 userAttribDecl
= sc
.userAttribDecl
;
842 void importAll(Scope
* sc
)
846 /*********************************************
847 * Search for ident as member of s.
849 * loc = location to print for error messages
850 * ident = identifier to search for
855 Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= IgnoreNone
)
857 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
861 extern (D
) final Dsymbol
search_correct(Identifier ident
)
863 /***************************************************
864 * Search for symbol with correct spelling.
866 extern (D
) Dsymbol
symbol_search_fp(const(char)[] seed
, out int cost
)
868 /* If not in the lexer's string table, it certainly isn't in the symbol table.
869 * Doing this first is a lot faster.
873 Identifier id
= Identifier
.lookup(seed
);
876 cost
= 0; // all the same cost
879 return s
.search(Loc
.initial
, id
, IgnoreErrors
);
883 return null; // don't do it for speculative compiles; too time consuming
884 // search for exact name first
885 if (auto s
= search(Loc
.initial
, ident
, IgnoreErrors
))
887 return speller
!symbol_search_fp(ident
.toString());
890 /***************************************
891 * Search for identifier id as a member of `this`.
892 * `id` may be a template instance.
895 * loc = location to print the error messages
896 * sc = the scope where the symbol is located
897 * id = the id of the symbol
898 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
901 * symbol found, NULL if not
903 extern (D
) final Dsymbol
searchX(const ref Loc loc
, Scope
* sc
, RootObject id
, int flags
)
905 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
906 Dsymbol s
= toAlias();
908 if (Declaration d
= s
.isDeclaration())
912 .error(loc
, "circular reference to `%s`", d
.toPrettyChars());
916 switch (id
.dyncast())
918 case DYNCAST
.identifier
:
919 sm
= s
.search(loc
, cast(Identifier
)id
, flags
);
921 case DYNCAST
.dsymbol
:
923 // It's a template instance
924 //printf("\ttemplate instance id\n");
925 Dsymbol st
= cast(Dsymbol
)id
;
926 TemplateInstance ti
= st
.isTemplateInstance();
927 sm
= s
.search(loc
, ti
.name
);
930 sm
= s
.search_correct(ti
.name
);
932 .error(loc
, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti
.name
.toChars(), s
.kind(), s
.toPrettyChars(), sm
.kind(), sm
.toChars());
934 .error(loc
, "template identifier `%s` is not a member of %s `%s`", ti
.name
.toChars(), s
.kind(), s
.toPrettyChars());
938 TemplateDeclaration td
= sm
.isTemplateDeclaration();
941 .error(loc
, "`%s.%s` is not a template, it is a %s", s
.toPrettyChars(), ti
.name
.toChars(), sm
.kind());
946 ti
.dsymbolSemantic(sc
);
951 case DYNCAST
.expression
:
958 bool overloadInsert(Dsymbol s
)
960 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
964 /*********************************
966 * SIZE_INVALID when the size cannot be determined
968 d_uns64
size(const ref Loc loc
)
970 error("Dsymbol `%s` has no size", toChars());
979 // is a 'this' required to access the member
980 inout(AggregateDeclaration
) isThis() inout
985 // is Dsymbol exported?
986 bool isExport() const
991 // is Dsymbol imported?
992 bool isImportedSymbol() const
997 // is Dsymbol deprecated?
998 bool isDeprecated() @safe @nogc pure nothrow const
1003 bool isOverloadable() const
1008 // is this a LabelDsymbol()?
1009 LabelDsymbol
isLabel()
1014 /// Returns an AggregateDeclaration when toParent() is that.
1015 final inout(AggregateDeclaration
) isMember() inout
1017 //printf("Dsymbol::isMember() %s\n", toChars());
1018 auto p
= toParent();
1019 //printf("parent is %s %s\n", p.kind(), p.toChars());
1020 return p ? p
.isAggregateDeclaration() : null;
1023 /// Returns an AggregateDeclaration when toParent2() is that.
1024 final inout(AggregateDeclaration
) isMember2() inout
1026 //printf("Dsymbol::isMember2() '%s'\n", toChars());
1027 auto p
= toParent2();
1028 //printf("parent is %s %s\n", p.kind(), p.toChars());
1029 return p ? p
.isAggregateDeclaration() : null;
1032 /// Returns an AggregateDeclaration when toParentDecl() is that.
1033 final inout(AggregateDeclaration
) isMemberDecl() inout
1035 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1036 auto p
= toParentDecl();
1037 //printf("parent is %s %s\n", p.kind(), p.toChars());
1038 return p ? p
.isAggregateDeclaration() : null;
1041 /// Returns an AggregateDeclaration when toParentLocal() is that.
1042 final inout(AggregateDeclaration
) isMemberLocal() inout
1044 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1045 auto p
= toParentLocal();
1046 //printf("parent is %s %s\n", p.kind(), p.toChars());
1047 return p ? p
.isAggregateDeclaration() : null;
1050 // is this a member of a ClassDeclaration?
1051 final ClassDeclaration
isClassMember()
1053 auto ad
= isMember();
1054 return ad ? ad
.isClassDeclaration() : null;
1063 // need a 'this' pointer?
1069 /*************************************
1071 Visibility
visible() pure nothrow @nogc @safe
1073 return Visibility(Visibility
.Kind
.public_
);
1076 /**************************************
1078 * Used for template instantiations.
1079 * If s is NULL, allocate the new object, otherwise fill it in.
1081 Dsymbol
syntaxCopy(Dsymbol s
)
1083 printf("%s %s\n", kind(), toChars());
1087 /**************************************
1088 * Determine if this symbol is only one.
1090 * false, *ps = NULL: There are 2 or more symbols
1091 * true, *ps = NULL: There are zero symbols
1092 * true, *ps = symbol: The one and only one symbol
1094 bool oneMember(Dsymbol
* ps
, Identifier ident
)
1096 //printf("Dsymbol::oneMember()\n");
1101 /*****************************************
1102 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1104 extern (D
) static bool oneMembers(Dsymbols
* members
, Dsymbol
* ps
, Identifier ident
)
1106 //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1114 for (size_t i
= 0; i
< members
.dim
; i
++)
1116 Dsymbol sx
= (*members
)[i
];
1117 bool x
= sx
.oneMember(ps
, ident
);
1118 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1121 //printf("\tfalse 1\n");
1122 assert(*ps
is null);
1128 if (!(*ps
).ident ||
!(*ps
).ident
.equals(ident
))
1132 else if (s
.isOverloadable() && (*ps
).isOverloadable())
1134 // keep head of overload set
1135 FuncDeclaration f1
= s
.isFuncDeclaration();
1136 FuncDeclaration f2
= (*ps
).isFuncDeclaration();
1139 assert(!f1
.isFuncAliasDeclaration());
1140 assert(!f2
.isFuncAliasDeclaration());
1141 for (; f1
!= f2
; f1
= f1
.overnext0
)
1143 if (f1
.overnext0
is null)
1151 else // more than one symbol
1154 //printf("\tfalse 2\n");
1159 *ps
= s
; // s is the one symbol, null if none
1160 //printf("\ttrue\n");
1164 void setFieldOffset(AggregateDeclaration ad
, ref FieldState fieldState
, bool isunion
)
1168 /*****************************************
1169 * Is Dsymbol a variable that contains pointers?
1173 //printf("Dsymbol::hasPointers() %s\n", toChars());
1177 bool hasStaticCtorOrDtor()
1179 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1183 void addLocalClass(ClassDeclarations
*)
1187 void addObjcSymbols(ClassDeclarations
* classes
, ClassDeclarations
* categories
)
1191 void checkCtorConstInit()
1195 /****************************************
1196 * Add documentation comment to Dsymbol.
1197 * Ignore NULL comments.
1199 void addComment(const(char)* comment
)
1202 // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
1204 this.comment
= comment
;
1205 else if (comment
&& strcmp(cast(char*)comment
, cast(char*)this.comment
) != 0)
1207 // Concatenate the two
1208 this.comment
= Lexer
.combineComments(this.comment
.toDString(), comment
.toDString(), true);
1212 /****************************************
1213 * Returns true if this symbol is defined in a non-root module without instantiation.
1215 final bool inNonRoot()
1218 for (; s
; s
= s
.toParent())
1220 if (auto ti
= s
.isTemplateInstance())
1224 if (auto m
= s
.isModule())
1236 override void accept(Visitor v
)
1241 pure nothrow @safe @nogc:
1243 // Eliminate need for dynamic_cast
1244 inout(Package
) isPackage() inout { return null; }
1245 inout(Module
) isModule() inout { return null; }
1246 inout(EnumMember
) isEnumMember() inout { return null; }
1247 inout(TemplateDeclaration
) isTemplateDeclaration() inout { return null; }
1248 inout(TemplateInstance
) isTemplateInstance() inout { return null; }
1249 inout(TemplateMixin
) isTemplateMixin() inout { return null; }
1250 inout(ForwardingAttribDeclaration
) isForwardingAttribDeclaration() inout { return null; }
1251 inout(Nspace
) isNspace() inout { return null; }
1252 inout(Declaration
) isDeclaration() inout { return null; }
1253 inout(StorageClassDeclaration
) isStorageClassDeclaration() inout { return null; }
1254 inout(ExpressionDsymbol
) isExpressionDsymbol() inout { return null; }
1255 inout(AliasAssign
) isAliasAssign() inout { return null; }
1256 inout(ThisDeclaration
) isThisDeclaration() inout { return null; }
1257 inout(BitFieldDeclaration
) isBitFieldDeclaration() inout { return null; }
1258 inout(TypeInfoDeclaration
) isTypeInfoDeclaration() inout { return null; }
1259 inout(TupleDeclaration
) isTupleDeclaration() inout { return null; }
1260 inout(AliasDeclaration
) isAliasDeclaration() inout { return null; }
1261 inout(AggregateDeclaration
) isAggregateDeclaration() inout { return null; }
1262 inout(FuncDeclaration
) isFuncDeclaration() inout { return null; }
1263 inout(FuncAliasDeclaration
) isFuncAliasDeclaration() inout { return null; }
1264 inout(OverDeclaration
) isOverDeclaration() inout { return null; }
1265 inout(FuncLiteralDeclaration
) isFuncLiteralDeclaration() inout { return null; }
1266 inout(CtorDeclaration
) isCtorDeclaration() inout { return null; }
1267 inout(PostBlitDeclaration
) isPostBlitDeclaration() inout { return null; }
1268 inout(DtorDeclaration
) isDtorDeclaration() inout { return null; }
1269 inout(StaticCtorDeclaration
) isStaticCtorDeclaration() inout { return null; }
1270 inout(StaticDtorDeclaration
) isStaticDtorDeclaration() inout { return null; }
1271 inout(SharedStaticCtorDeclaration
) isSharedStaticCtorDeclaration() inout { return null; }
1272 inout(SharedStaticDtorDeclaration
) isSharedStaticDtorDeclaration() inout { return null; }
1273 inout(InvariantDeclaration
) isInvariantDeclaration() inout { return null; }
1274 inout(UnitTestDeclaration
) isUnitTestDeclaration() inout { return null; }
1275 inout(NewDeclaration
) isNewDeclaration() inout { return null; }
1276 inout(VarDeclaration
) isVarDeclaration() inout { return null; }
1277 inout(VersionSymbol
) isVersionSymbol() inout { return null; }
1278 inout(DebugSymbol
) isDebugSymbol() inout { return null; }
1279 inout(ClassDeclaration
) isClassDeclaration() inout { return null; }
1280 inout(StructDeclaration
) isStructDeclaration() inout { return null; }
1281 inout(UnionDeclaration
) isUnionDeclaration() inout { return null; }
1282 inout(InterfaceDeclaration
) isInterfaceDeclaration() inout { return null; }
1283 inout(ScopeDsymbol
) isScopeDsymbol() inout { return null; }
1284 inout(ForwardingScopeDsymbol
) isForwardingScopeDsymbol() inout { return null; }
1285 inout(WithScopeSymbol
) isWithScopeSymbol() inout { return null; }
1286 inout(ArrayScopeSymbol
) isArrayScopeSymbol() inout { return null; }
1287 inout(Import
) isImport() inout { return null; }
1288 inout(EnumDeclaration
) isEnumDeclaration() inout { return null; }
1289 inout(SymbolDeclaration
) isSymbolDeclaration() inout { return null; }
1290 inout(AttribDeclaration
) isAttribDeclaration() inout { return null; }
1291 inout(AnonDeclaration
) isAnonDeclaration() inout { return null; }
1292 inout(CPPNamespaceDeclaration
) isCPPNamespaceDeclaration() inout { return null; }
1293 inout(VisibilityDeclaration
) isVisibilityDeclaration() inout { return null; }
1294 inout(OverloadSet
) isOverloadSet() inout { return null; }
1295 inout(CompileDeclaration
) isCompileDeclaration() inout { return null; }
1298 /***********************************************************
1299 * Dsymbol that generates a scope
1301 extern (C
++) class ScopeDsymbol
: Dsymbol
1303 Dsymbols
* members
; // all Dsymbol's in this scope
1304 DsymbolTable symtab
; // members[] sorted into table
1305 uint endlinnum
; // the linnumber of the statement after the scope (0 if unknown)
1308 /// symbols whose members have been imported, i.e. imported modules and template mixins
1309 Dsymbols
* importedScopes
;
1310 Visibility
.Kind
* visibilities
; // array of Visibility.Kind, one for each import
1312 import dmd
.root
.bitarray
;
1313 BitArray accessiblePackages
, privateAccessiblePackages
;// whitelists of accessible (imported) packages
1316 final extern (D
) this()
1320 final extern (D
) this(Identifier ident
)
1325 final extern (D
) this(const ref Loc loc
, Identifier ident
)
1330 override ScopeDsymbol
syntaxCopy(Dsymbol s
)
1332 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1333 ScopeDsymbol sds
= s ?
cast(ScopeDsymbol
)s
: new ScopeDsymbol(ident
);
1334 sds
.comment
= comment
;
1335 sds
.members
= arraySyntaxCopy(members
);
1336 sds
.endlinnum
= endlinnum
;
1340 /*****************************************
1341 * This function is #1 on the list of functions that eat cpu time.
1342 * Be very, very careful about slowing it down.
1344 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= SearchLocalsOnly
)
1346 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1347 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1349 // Look in symbols declared in this module
1350 if (symtab
&& !(flags
& SearchImportsOnly
))
1352 //printf(" look in locals\n");
1353 auto s1
= symtab
.lookup(ident
);
1356 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1360 //printf(" not found in locals\n");
1362 // Look in imported scopes
1363 if (!importedScopes
)
1366 //printf(" look in imports\n");
1368 OverloadSet a
= null;
1369 // Look in imported modules
1370 for (size_t i
= 0; i
< importedScopes
.dim
; i
++)
1372 // If private import, don't search it
1373 if ((flags
& IgnorePrivateImports
) && visibilities
[i
] == Visibility
.Kind
.private_
)
1375 int sflags
= flags
& (IgnoreErrors | IgnoreAmbiguous
); // remember these in recursive searches
1376 Dsymbol ss
= (*importedScopes
)[i
];
1377 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1381 if (flags
& SearchLocalsOnly
)
1384 else // mixin template
1386 if (flags
& SearchImportsOnly
)
1389 sflags |
= SearchLocalsOnly
;
1392 /* Don't find private members if ss is a module
1394 Dsymbol s2
= ss
.search(loc
, ident
, sflags |
(ss
.isModule() ? IgnorePrivateImports
: IgnoreNone
));
1395 import dmd
.access
: symbolIsVisible
;
1396 if (!s2 ||
!(flags
& IgnoreSymbolVisibility
) && !symbolIsVisible(this, s2
))
1401 if (s
&& s
.isOverloadSet())
1402 a
= mergeOverloadSet(ident
, a
, s
);
1404 else if (s2
&& s
!= s2
)
1406 if (s
.toAlias() == s2
.toAlias() || s
.getType() == s2
.getType() && s
.getType())
1408 /* After following aliases, we found the same
1409 * symbol, so it's not an ambiguity. But if one
1410 * alias is deprecated or less accessible, prefer
1413 if (s
.isDeprecated() || s
.visible() < s2
.visible() && s2
.visible().kind
!= Visibility
.Kind
.none
)
1418 /* Two imports of the same module should be regarded as
1421 Import i1
= s
.isImport();
1422 Import i2
= s2
.isImport();
1423 if (!(i1
&& i2
&& (i1
.mod
== i2
.mod ||
(!i1
.parent
.isImport() && !i2
.parent
.isImport() && i1
.ident
.equals(i2
.ident
)))))
1425 /* https://issues.dlang.org/show_bug.cgi?id=8668
1426 * Public selective import adds AliasDeclaration in module.
1427 * To make an overload set, resolve aliases in here and
1428 * get actual overload roots which accessible via s and s2.
1432 /* If both s2 and s are overloadable (though we only
1433 * need to check s once)
1436 auto so2
= s2
.isOverloadSet();
1437 if ((so2 || s2
.isOverloadable()) && (a || s
.isOverloadable()))
1439 if (symbolIsVisible(this, s2
))
1441 a
= mergeOverloadSet(ident
, a
, s2
);
1443 if (!symbolIsVisible(this, s
))
1448 /* Two different overflow sets can have the same members
1449 * https://issues.dlang.org/show_bug.cgi?id=16709
1451 auto so
= s
.isOverloadSet();
1454 if (so
.a
.length
== so2
.a
.length
)
1456 foreach (j
; 0 .. so
.a
.length
)
1458 if (so
.a
[j
] !is so2
.a
[j
])
1461 continue; // the same
1467 if (flags
& IgnoreAmbiguous
) // if return NULL on ambiguity
1469 if (!(flags
& IgnoreErrors
))
1470 ScopeDsymbol
.multiplyDefined(loc
, s
, s2
);
1478 /* Build special symbol if we had multiple finds
1482 if (!s
.isOverloadSet())
1483 a
= mergeOverloadSet(ident
, a
, s
);
1486 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1489 //printf(" not found in imports\n");
1493 extern (D
) private OverloadSet
mergeOverloadSet(Identifier ident
, OverloadSet os
, Dsymbol s
)
1497 os
= new OverloadSet(ident
);
1500 if (OverloadSet os2
= s
.isOverloadSet())
1502 // Merge the cross-module overload set 'os2' into 'os'
1505 os
.a
.setDim(os2
.a
.dim
);
1506 memcpy(os
.a
.tdata(), os2
.a
.tdata(), (os
.a
[0]).sizeof
* os2
.a
.dim
);
1510 for (size_t i
= 0; i
< os2
.a
.dim
; i
++)
1512 os
= mergeOverloadSet(ident
, os
, os2
.a
[i
]);
1518 assert(s
.isOverloadable());
1519 /* Don't add to os[] if s is alias of previous sym
1521 for (size_t j
= 0; j
< os
.a
.dim
; j
++)
1523 Dsymbol s2
= os
.a
[j
];
1524 if (s
.toAlias() == s2
.toAlias())
1526 if (s2
.isDeprecated() ||
(s2
.visible() < s
.visible() && s
.visible().kind
!= Visibility
.Kind
.none
))
1539 void importScope(Dsymbol s
, Visibility visibility
)
1541 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1542 // No circular or redundant import's
1545 if (!importedScopes
)
1546 importedScopes
= new Dsymbols();
1549 for (size_t i
= 0; i
< importedScopes
.dim
; i
++)
1551 Dsymbol ss
= (*importedScopes
)[i
];
1552 if (ss
== s
) // if already imported
1554 if (visibility
.kind
> visibilities
[i
])
1555 visibilities
[i
] = visibility
.kind
; // upgrade access
1560 importedScopes
.push(s
);
1561 visibilities
= cast(Visibility
.Kind
*)mem
.xrealloc(visibilities
, importedScopes
.dim
* (visibilities
[0]).sizeof
);
1562 visibilities
[importedScopes
.dim
- 1] = visibility
.kind
;
1566 extern (D
) final void addAccessiblePackage(Package p
, Visibility visibility
)
1568 auto pary
= visibility
.kind
== Visibility
.Kind
.private_ ?
&privateAccessiblePackages
: &accessiblePackages
;
1569 if (pary
.length
<= p
.tag
)
1570 pary
.length
= p
.tag
+ 1;
1571 (*pary
)[p
.tag
] = true;
1574 bool isPackageAccessible(Package p
, Visibility visibility
, int flags
= 0)
1576 if (p
.tag
< accessiblePackages
.length
&& accessiblePackages
[p
.tag
] ||
1577 visibility
.kind
== Visibility
.Kind
.private_
&& p
.tag
< privateAccessiblePackages
.length
&& privateAccessiblePackages
[p
.tag
])
1579 foreach (i
, ss
; importedScopes ?
(*importedScopes
)[] : null)
1581 // only search visible scopes && imported modules should ignore private imports
1582 if (visibility
.kind
<= visibilities
[i
] &&
1583 ss
.isScopeDsymbol
.isPackageAccessible(p
, visibility
, IgnorePrivateImports
))
1589 override final bool isforwardRef()
1591 return (members
is null);
1594 static void multiplyDefined(const ref Loc loc
, Dsymbol s1
, Dsymbol s2
)
1598 printf("ScopeDsymbol::multiplyDefined()\n");
1599 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1
, s1
.toChars(), s1
.kind(), s1
.parent ? s1
.parent
.toChars() : "");
1600 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2
, s2
.toChars(), s2
.kind(), s2
.parent ? s2
.parent
.toChars() : "");
1604 .error(loc
, "%s `%s` at %s conflicts with %s `%s` at %s",
1605 s1
.kind(), s1
.toPrettyChars(), s1
.locToChars(),
1606 s2
.kind(), s2
.toPrettyChars(), s2
.locToChars());
1610 if (auto so
= s1
.isOverloadSet())
1612 printf("first %p:\n", so
);
1615 printf(" %p %s `%s` at %s\n", s
, s
.kind(), s
.toPrettyChars(), s
.locToChars());
1618 if (auto so
= s2
.isOverloadSet())
1620 printf("second %p:\n", so
);
1623 printf(" %p %s `%s` at %s\n", s
, s
.kind(), s
.toPrettyChars(), s
.locToChars());
1630 s1
.error(s1
.loc
, "conflicts with %s `%s` at %s", s2
.kind(), s2
.toPrettyChars(), s2
.locToChars());
1634 override const(char)* kind() const
1636 return "ScopeDsymbol";
1639 /*******************************************
1640 * Look for member of the form:
1641 * const(MemberInfo)[] getMembers(string);
1642 * Returns NULL if not found
1644 final FuncDeclaration
findGetMembers()
1646 Dsymbol s
= search_function(this, Id
.getmembers
);
1647 FuncDeclaration fdx
= s ? s
.isFuncDeclaration() : null;
1651 __gshared TypeFunction tfgetmembers
;
1655 auto parameters
= new Parameters();
1656 Parameters
* p
= new Parameter(STC
.in_
, Type
.tchar
.constOf().arrayOf(), null, null);
1659 tfgetmembers
= new TypeFunction(parameters
, tret
, VarArg
.none
, LINK
.d
);
1660 tfgetmembers
= cast(TypeFunction
)tfgetmembers
.dsymbolSemantic(Loc
.initial
, &sc
);
1663 fdx
= fdx
.overloadExactMatch(tfgetmembers
);
1665 if (fdx
&& fdx
.isVirtual())
1670 /********************************
1671 * Insert Dsymbol in table.
1675 * null if already in table, `s` if inserted
1677 Dsymbol
symtabInsert(Dsymbol s
)
1679 return symtab
.insert(s
);
1682 /****************************************
1683 * Look up identifier in symbol table.
1686 * id = identifier to look up
1688 * Dsymbol if found, null if not
1690 Dsymbol
symtabLookup(Dsymbol s
, Identifier id
)
1692 return symtab
.lookup(id
);
1695 /****************************************
1696 * Return true if any of the members are static ctors or static dtors, or if
1697 * any members have members that are.
1699 override bool hasStaticCtorOrDtor()
1703 for (size_t i
= 0; i
< members
.dim
; i
++)
1705 Dsymbol member
= (*members
)[i
];
1706 if (member
.hasStaticCtorOrDtor())
1713 extern (D
) alias ForeachDg
= int delegate(size_t idx
, Dsymbol s
);
1715 /***************************************
1716 * Expands attribute declarations in members in depth first
1717 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1719 * If dg returns !=0, stops and returns that value else returns 0.
1720 * Use this function to avoid the O(N + N^2/2) complexity of
1721 * calculating dim and calling N times getNth.
1723 * last value returned by dg()
1725 extern (D
) static int _foreach(Scope
* sc
, Dsymbols
* members
, scope ForeachDg dg
, size_t
* pn
= null)
1730 size_t n
= pn ?
*pn
: 0; // take over index
1732 foreach (size_t i
; 0 .. members
.dim
)
1734 Dsymbol s
= (*members
)[i
];
1735 if (AttribDeclaration a
= s
.isAttribDeclaration())
1736 result
= _foreach(sc
, a
.include(sc
), dg
, &n
);
1737 else if (TemplateMixin tm
= s
.isTemplateMixin())
1738 result
= _foreach(sc
, tm
.members
, dg
, &n
);
1739 else if (s
.isTemplateInstance())
1742 else if (s
.isUnitTestDeclaration())
1746 result
= dg(n
++, s
);
1751 *pn
= n
; // update index
1755 override final inout(ScopeDsymbol
) isScopeDsymbol() inout
1760 override void accept(Visitor v
)
1766 /***********************************************************
1767 * With statement scope
1769 extern (C
++) final class WithScopeSymbol
: ScopeDsymbol
1771 WithStatement withstate
;
1773 extern (D
) this(WithStatement withstate
)
1775 this.withstate
= withstate
;
1778 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= SearchLocalsOnly
)
1780 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1781 if (flags
& SearchImportsOnly
)
1783 // Acts as proxy to the with class declaration
1785 Expression eold
= null;
1786 for (Expression e
= withstate
.exp
; e
!= eold
; e
= resolveAliasThis(_scope
, e
))
1788 if (e
.op
== TOK
.scope_
)
1790 s
= (cast(ScopeExp
)e
).sds
;
1792 else if (e
.op
== TOK
.type
)
1794 s
= e
.type
.toDsymbol(null);
1798 Type t
= e
.type
.toBasetype();
1799 s
= t
.toDsymbol(null);
1803 s
= s
.search(loc
, ident
, flags
);
1812 override inout(WithScopeSymbol
) isWithScopeSymbol() inout
1817 override void accept(Visitor v
)
1823 /***********************************************************
1824 * Array Index/Slice scope
1826 extern (C
++) final class ArrayScopeSymbol
: ScopeDsymbol
1828 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1829 // Discriminated using DYNCAST and, for expressions, also TOK
1830 private RootObject arrayContent
;
1833 extern (D
) this(Scope
* sc
, Expression exp
)
1835 super(exp
.loc
, null);
1836 assert(exp
.op
== TOK
.index || exp
.op
== TOK
.slice || exp
.op
== TOK
.array
);
1838 this.arrayContent
= exp
;
1841 extern (D
) this(Scope
* sc
, TypeTuple type
)
1844 this.arrayContent
= type
;
1847 extern (D
) this(Scope
* sc
, TupleDeclaration td
)
1850 this.arrayContent
= td
;
1853 /// This override is used to solve `$`
1854 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= IgnoreNone
)
1856 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1857 if (ident
!= Id
.dollar
)
1860 VarDeclaration
* pvar
;
1863 static Dsymbol
dollarFromTypeTuple(const ref Loc loc
, TypeTuple tt
, Scope
* sc
)
1866 /* $ gives the number of type entries in the type tuple
1868 auto v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, null);
1869 Expression e
= new IntegerExp(Loc
.initial
, tt
.arguments
.dim
, Type
.tsize_t
);
1870 v
._init
= new ExpInitializer(Loc
.initial
, e
);
1871 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
1872 v
.dsymbolSemantic(sc
);
1876 const DYNCAST kind
= arrayContent
.dyncast();
1877 if (kind
== DYNCAST
.dsymbol
)
1879 TupleDeclaration td
= cast(TupleDeclaration
) arrayContent
;
1880 /* $ gives the number of elements in the tuple
1882 auto v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, null);
1883 Expression e
= new IntegerExp(Loc
.initial
, td
.objects
.dim
, Type
.tsize_t
);
1884 v
._init
= new ExpInitializer(Loc
.initial
, e
);
1885 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
1886 v
.dsymbolSemantic(sc
);
1889 if (kind
== DYNCAST
.type
)
1891 return dollarFromTypeTuple(loc
, cast(TypeTuple
) arrayContent
, sc
);
1893 Expression exp
= cast(Expression
) arrayContent
;
1894 if (auto ie
= exp
.isIndexExp())
1896 /* array[index] where index is some function of $
1898 pvar
= &ie
.lengthVar
;
1901 else if (auto se
= exp
.isSliceExp())
1903 /* array[lwr .. upr] where lwr or upr is some function of $
1905 pvar
= &se
.lengthVar
;
1908 else if (auto ae
= exp
.isArrayExp())
1910 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1911 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1913 pvar
= &ae
.lengthVar
;
1918 /* Didn't find $, look in enclosing scope(s).
1922 ce
= ce
.lastComma();
1923 /* If we are indexing into an array that is really a type
1924 * tuple, rewrite this as an index into a type tuple and
1927 if (auto te
= ce
.isTypeExp())
1929 if (auto ttp
= te
.type
.isTypeTuple())
1930 return dollarFromTypeTuple(loc
, ttp
, sc
);
1932 /* *pvar is lazily initialized, so if we refer to $
1933 * multiple times, it gets set only once.
1935 if (!*pvar
) // if not already initialized
1937 /* Create variable v and set it to the value of $
1941 if (auto tupexp
= ce
.isTupleExp())
1943 /* It is for an expression tuple, so the
1944 * length will be a const.
1946 Expression e
= new IntegerExp(Loc
.initial
, tupexp
.exps
.dim
, Type
.tsize_t
);
1947 v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, new ExpInitializer(Loc
.initial
, e
));
1948 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
1950 else if (ce
.type
&& (t
= ce
.type
.toBasetype()) !is null && (t
.ty
== Tstruct || t
.ty
== Tclass
))
1952 // Look for opDollar
1953 assert(exp
.op
== TOK
.array || exp
.op
== TOK
.slice
);
1954 AggregateDeclaration ad
= isAggregate(t
);
1956 Dsymbol s
= ad
.search(loc
, Id
.opDollar
);
1957 if (!s
) // no dollar exists -- search in higher scope
1960 Expression e
= null;
1961 // Check for multi-dimensional opDollar(dim) template.
1962 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
1965 if (exp
.op
== TOK
.array
)
1967 dim
= (cast(ArrayExp
)exp
).currentDimension
;
1969 else if (exp
.op
== TOK
.slice
)
1971 dim
= 0; // slices are currently always one-dimensional
1977 auto tiargs
= new Objects();
1978 Expression edim
= new IntegerExp(Loc
.initial
, dim
, Type
.tsize_t
);
1979 edim
= edim
.expressionSemantic(sc
);
1981 e
= new DotTemplateInstanceExp(loc
, ce
, td
.ident
, tiargs
);
1985 /* opDollar exists, but it's not a template.
1986 * This is acceptable ONLY for single-dimension indexing.
1987 * Note that it's impossible to have both template & function opDollar,
1988 * because both take no arguments.
1990 if (exp
.op
== TOK
.array
&& (cast(ArrayExp
)exp
).arguments
.dim
!= 1)
1992 exp
.error("`%s` only defines opDollar for one dimension", ad
.toChars());
1995 Declaration d
= s
.isDeclaration();
1997 e
= new DotVarExp(loc
, ce
, d
);
1999 e
= e
.expressionSemantic(sc
);
2001 exp
.error("`%s` has no value", e
.toChars());
2002 t
= e
.type
.toBasetype();
2003 if (t
&& t
.ty
== Tfunction
)
2004 e
= new CallExp(e
.loc
, e
);
2005 v
= new VarDeclaration(loc
, null, Id
.dollar
, new ExpInitializer(Loc
.initial
, e
));
2006 v
.storage_class |
= STC
.temp | STC
.ctfe | STC
.rvalue
;
2010 /* For arrays, $ will either be a compile-time constant
2011 * (in which case its value in set during constant-folding),
2012 * or a variable (in which case an expression is created in
2015 auto e
= new VoidInitializer(Loc
.initial
);
2016 e
.type
= Type
.tsize_t
;
2017 v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, e
);
2018 v
.storage_class |
= STC
.temp | STC
.ctfe
; // it's never a true static variable
2022 (*pvar
).dsymbolSemantic(sc
);
2026 override inout(ArrayScopeSymbol
) isArrayScopeSymbol() inout
2031 override void accept(Visitor v
)
2037 /***********************************************************
2040 extern (C
++) final class OverloadSet
: Dsymbol
2042 Dsymbols a
; // array of Dsymbols
2044 extern (D
) this(Identifier ident
, OverloadSet os
= null)
2049 a
.pushSlice(os
.a
[]);
2053 void push(Dsymbol s
)
2058 override inout(OverloadSet
) isOverloadSet() inout
2063 override const(char)* kind() const
2065 return "overloadset";
2068 override void accept(Visitor v
)
2074 /***********************************************************
2075 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2076 * ForwardingScopeDeclaration to forward symbol insertions to another
2077 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2080 extern (C
++) final class ForwardingScopeDsymbol
: ScopeDsymbol
2082 /*************************
2083 * Symbol to forward insertions to.
2084 * Can be `null` before being lazily initialized.
2086 ScopeDsymbol forward
;
2087 extern (D
) this(ScopeDsymbol forward
)
2090 this.forward
= forward
;
2092 override Dsymbol
symtabInsert(Dsymbol s
)
2095 if (auto d
= s
.isDeclaration())
2097 if (d
.storage_class
& STC
.local
)
2099 // Symbols with storage class STC.local are not
2100 // forwarded, but stored in the local symbol
2101 // table. (Those are the `static foreach` variables.)
2104 symtab
= new DsymbolTable();
2106 return super.symtabInsert(s
); // insert locally
2109 if (!forward
.symtab
)
2111 forward
.symtab
= new DsymbolTable();
2113 // Non-STC.local symbols are forwarded to `forward`.
2114 return forward
.symtabInsert(s
);
2117 /************************
2118 * This override handles the following two cases:
2119 * static foreach (i, i; [0]) { ... }
2121 * static foreach (i; [0]) { enum i = 2; }
2123 override Dsymbol
symtabLookup(Dsymbol s
, Identifier id
)
2126 // correctly diagnose clashing foreach loop variables.
2127 if (auto d
= s
.isDeclaration())
2129 if (d
.storage_class
& STC
.local
)
2133 symtab
= new DsymbolTable();
2135 return super.symtabLookup(s
,id
);
2138 // Declarations within `static foreach` do not clash with
2139 // `static foreach` loop variables.
2140 if (!forward
.symtab
)
2142 forward
.symtab
= new DsymbolTable();
2144 return forward
.symtabLookup(s
,id
);
2147 override void importScope(Dsymbol s
, Visibility visibility
)
2149 forward
.importScope(s
, visibility
);
2152 override const(char)* kind()const{ return "local scope"; }
2154 override inout(ForwardingScopeDsymbol
) isForwardingScopeDsymbol() inout
2162 * Class that holds an expression in a Dsymbol wrapper.
2163 * This is not an AST node, but a class used to pass
2164 * an expression as a function parameter of type Dsymbol.
2166 extern (C
++) final class ExpressionDsymbol
: Dsymbol
2169 this(Expression exp
)
2175 override inout(ExpressionDsymbol
) isExpressionDsymbol() inout
2181 /**********************************************
2182 * Encapsulate assigning to an alias:
2183 * `identifier = type;`
2184 * `identifier = symbol;`
2185 * where `identifier` is an AliasDeclaration in scope.
2187 extern (C
++) final class AliasAssign
: Dsymbol
2189 Identifier ident
; /// Dsymbol's ident will be null, as this class is anonymous
2190 Type type
; /// replace previous RHS of AliasDeclaration with `type`
2191 Dsymbol aliassym
; /// replace previous RHS of AliasDeclaration with `aliassym`
2192 /// only one of type and aliassym can be != null
2194 extern (D
) this(const ref Loc loc
, Identifier ident
, Type type
, Dsymbol aliassym
)
2199 this.aliassym
= aliassym
;
2202 override AliasAssign
syntaxCopy(Dsymbol s
)
2205 AliasAssign aa
= new AliasAssign(loc
, ident
,
2206 type ? type
.syntaxCopy() : null,
2207 aliassym ? aliassym
.syntaxCopy(null) : null);
2211 override inout(AliasAssign
) isAliasAssign() inout
2216 override const(char)* kind() const
2218 return "alias assignment";
2221 override void accept(Visitor v
)
2227 /***********************************************************
2228 * Table of Dsymbol's
2230 extern (C
++) final class DsymbolTable
: RootObject
2232 AssocArray
!(Identifier
, Dsymbol
) tab
;
2234 /***************************
2235 * Look up Identifier in symbol table
2237 * ident = identifer to look up
2239 * Dsymbol if found, null if not
2241 Dsymbol
lookup(const Identifier ident
)
2243 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2248 * Replace existing symbol in symbol table with `s`.
2249 * If it's not there, add it.
2251 * s = replacement symbol with same identifier
2253 void update(Dsymbol s
)
2255 *tab
.getLvalue(s
.ident
) = s
;
2258 /**************************
2259 * Insert Dsymbol in table.
2263 * null if already in table, `s` if inserted
2265 Dsymbol
insert(Dsymbol s
)
2267 return insert(s
.ident
, s
);
2270 /**************************
2271 * Insert Dsymbol in table.
2273 * ident = identifier to serve as index
2276 * null if already in table, `s` if inserted
2278 Dsymbol
insert(const Identifier ident
, Dsymbol s
)
2280 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2281 Dsymbol
* ps
= tab
.getLvalue(ident
);
2283 return null; // already in table
2290 * number of symbols in symbol table
2292 size_t
length() const pure
2298 /**********************************************
2299 * ImportC tag symbols sit in a parallel symbol table,
2300 * so that this C code works:
2306 * But there are relatively few such tag symbols, so that would be
2307 * a waste of memory and complexity. An additional problem is we'd like the D side
2308 * to find the tag symbols with ordinary lookup, not lookup in both
2309 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2310 * The solution is to put the tag symbols that conflict into an associative
2311 * array, indexed by the address of the ordinary symbol that conflicts with it.
2312 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2313 * A side effect of our approach is that D code cannot access a tag symbol that is
2314 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2315 * has mentioned it when importing C headers. If someone wants to do it,
2316 * too bad so sad. Change the C code.
2317 * This function fixes up the symbol table when faced with adding a new symbol
2318 * `s` when there is an existing symbol `s2` with the same name.
2319 * C also allows forward and prototype declarations of tag symbols,
2320 * this function merges those.
2323 * s = symbol to add to symbol table
2324 * s2 = existing declaration
2325 * sds = symbol table
2327 * if s and s2 are successfully put in symbol table then return the merged symbol,
2328 * null if they conflict
2330 Dsymbol
handleTagSymbols(ref Scope sc
, Dsymbol s
, Dsymbol s2
, ScopeDsymbol sds
)
2333 if (log
) printf("handleTagSymbols('%s')\n", s
.toChars());
2334 auto sd
= s
.isScopeDsymbol(); // new declaration
2335 auto sd2
= s2
.isScopeDsymbol(); // existing declaration
2339 /* Look in tag table
2341 if (log
) printf(" look in tag table\n");
2342 if (auto p
= cast(void*)s2
in sc
._module
.tagSymTab
)
2345 sd2
= s2tag
.isScopeDsymbol();
2346 assert(sd2
); // only tags allowed in tag symbol table
2350 if (sd
&& sd2
) // `s` is a tag, `sd2` is the same tag
2352 if (log
) printf(" tag is already defined\n");
2354 if (sd
.kind() != sd2
.kind()) // being enum/struct/union must match
2355 return null; // conflict
2357 /* Not a redeclaration if one is a forward declaration.
2358 * Move members to the first declared type, which is sd2.
2363 return sd2
; // ignore the sd redeclaration
2365 else if (sd
.members
)
2367 sd2
.members
= sd
.members
; // transfer definition to sd2
2372 return sd2
; // ignore redeclaration
2374 else if (sd
) // `s` is a tag, `s2` is not
2376 if (log
) printf(" s is tag, s2 is not\n");
2377 /* add `s` as tag indexed by s2
2379 sc
._module
.tagSymTab
[cast(void*)s2
] = s
;
2382 else if (s2
is sd2
) // `s2` is a tag, `s` is not
2384 if (log
) printf(" s2 is tag, s is not\n");
2385 /* replace `s2` in symbol table with `s`,
2386 * then add `s2` as tag indexed by `s`
2388 sds
.symtab
.update(s
);
2389 sc
._module
.tagSymTab
[cast(void*)s
] = s2
;
2392 if (log
) printf(" collision\n");
2397 /**********************************************
2398 * ImportC allows redeclarations of C variables, functions and typedefs.
2404 * Attempt to merge them.
2407 * s = symbol to add to symbol table
2408 * s2 = existing declaration
2409 * sds = symbol table
2411 * if s and s2 are successfully put in symbol table then return the merged symbol,
2412 * null if they conflict
2414 Dsymbol
handleSymbolRedeclarations(ref Scope sc
, Dsymbol s
, Dsymbol s2
, ScopeDsymbol sds
)
2417 if (log
) printf("handleSymbolRedeclarations('%s')\n", s
.toChars());
2419 static Dsymbol
collision()
2421 if (log
) printf(" collision\n");
2425 auto vd
= s
.isVarDeclaration(); // new declaration
2426 auto vd2
= s2
.isVarDeclaration(); // existing declaration
2429 // if one is `static` and the other isn't
2430 if ((vd
.storage_class ^ vd2
.storage_class
) & STC
.static_
)
2433 const i1
= vd
._init
&& ! vd
._init
.isVoidInitializer();
2434 const i2
= vd2
._init
&& !vd2
._init
.isVoidInitializer();
2437 return collision(); // can't both have initializers
2442 /* BUG: the types should match, which needs semantic() to be run on it
2447 * long x; // collision
2448 * We incorrectly ignore these collisions
2453 auto fd
= s
.isFuncDeclaration(); // new declaration
2454 auto fd2
= s2
.isFuncDeclaration(); // existing declaration
2457 // if one is `static` and the other isn't
2458 if ((fd
.storage_class ^ fd2
.storage_class
) & STC
.static_
)
2461 if (fd
.fbody
&& fd2
.fbody
)
2462 return collision(); // can't both have bodies
2467 /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2468 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2473 auto td
= s
.isAliasDeclaration(); // new declaration
2474 auto td2
= s2
.isAliasDeclaration(); // existing declaration
2477 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2478 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.