2 * The base class for a D symbol, which can be a module, variable, function, enum, etc.
4 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d)
8 * Documentation: https://dlang.org/phobos/dmd_dsymbol.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d
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
;
54 import dmd
.staticassert
;
58 /***************************************
59 * Calls dg(Dsymbol *sym) for each Dsymbol.
60 * If dg returns !=0, stops and returns that value else returns 0.
63 * dg = delegate to call for each Dsymbol
65 * last value returned by dg()
67 * See_Also: $(REF each, dmd, root, array)
69 int foreachDsymbol(Dsymbols
* symbols
, scope int delegate(Dsymbol
) dg
)
74 /* Do not use foreach, as the size of the array may expand during iteration
76 for (size_t i
= 0; i
< symbols
.dim
; ++i
)
78 Dsymbol s
= (*symbols
)[i
];
87 /***************************************
88 * Calls dg(Dsymbol *sym) for each Dsymbol.
91 * dg = delegate to call for each Dsymbol
93 * See_Also: $(REF each, dmd, root, array)
95 void foreachDsymbol(Dsymbols
* symbols
, scope void delegate(Dsymbol
) dg
)
100 /* Do not use foreach, as the size of the array may expand during iteration
102 for (size_t i
= 0; i
< symbols
.dim
; ++i
)
104 Dsymbol s
= (*symbols
)[i
];
115 extern (D
) this(uint old
) nothrow
120 extern (C
++) ~this() nothrow
145 this(Visibility
.Kind kind
) pure nothrow @nogc @safe
151 * Checks if `this` is less or more visible than `other`
154 * other = Visibility to compare `this` to.
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`.
163 int opCmp(const Visibility other
) const pure nothrow @nogc @safe
165 return this.kind
- other
.kind
;
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_
));
177 * Checks if `this` is absolutely identical visibility attribute to `other`
179 bool opEquals(ref const Visibility other
) const
181 if (this.kind
== other
.kind
)
183 if (this.kind
== Visibility
.Kind
.package_
)
184 return this.pkg
== other
.pkg
;
193 initial
, // initial state
194 semantic
, // semantic() started
195 semanticdone
, // semantic() done
196 semantic2
, // semantic2() started
197 semantic2done
, // semantic2() done
198 semantic3
, // semantic3() started
199 semantic3done
, // semantic3() done
200 inline
, // inline started
201 inlinedone
, // inline done
202 obj
, // toObjFile() run
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
218 IgnoreSymbolVisibility
= 0x80, // also find private and package protected symbols
219 TagNameSpace
= 0x100, // search ImportC tag symbol table
222 /***********************************************************
223 * Struct/Class/Union field state.
224 * Used for transitory information when setting field offsets, such
229 uint offset
; /// byte offset for next field
231 uint fieldOffset
; /// byte offset for the start of the bit field
232 uint fieldSize
; /// byte size of field
233 uint fieldAlign
; /// byte alignment of field
234 uint bitOffset
; /// bit offset for field
236 bool inFlight
; /// bit field is in flight
239 /***********************************************************
241 extern (C
++) class Dsymbol
: ASTNode
245 /// C++ namespace this symbol belongs to
246 CPPNamespaceDeclaration cppnamespace
;
247 Symbol
* csym
; // symbol for code generator
248 const Loc loc
; // where defined
249 Scope
* _scope
; // !=null means context to use for semantic()
250 const(char)* prettystring
; // cached value of toPrettyChars()
251 bool errors
; // this symbol failed to pass semantic()
252 PASS semanticRun
= PASS
.initial
;
253 ushort localNum
; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
255 DeprecatedDeclaration depdecl
; // customized deprecation message
256 UserAttributeDeclaration userAttribDecl
; // user defined attributes
258 final extern (D
) this() nothrow
260 //printf("Dsymbol::Dsymbol(%p)\n", this);
261 loc
= Loc(null, 0, 0);
264 final extern (D
) this(Identifier ident
) nothrow
266 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
267 this.loc
= Loc(null, 0, 0);
271 final extern (D
) this(const ref Loc loc
, Identifier ident
) nothrow
273 //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
278 static Dsymbol
create(Identifier ident
) nothrow
280 return new Dsymbol(ident
);
283 override const(char)* toChars() const
285 return ident ? ident
.toChars() : "__anonymous";
288 // helper to print fully qualified (template) arguments
289 const(char)* toPrettyCharsHelper()
294 final const(Loc
) getLoc()
296 if (!loc
.isValid()) // avoid bug 5861.
297 if (const m
= getModule())
298 return Loc(m
.srcfile
.toChars(), 0, 0);
302 final const(char)* locToChars()
304 return getLoc().toChars();
307 override bool equals(const RootObject o
) const
311 if (o
.dyncast() != DYNCAST
.dsymbol
)
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
)
322 final bool isAnonymous() const
324 return ident
is null || ident
.isAnonymous
;
327 extern(D
) private const(char)[] prettyFormatHelper()
329 const cstr
= toPrettyChars();
330 return '`' ~ cstr
.toDString() ~ "`\0";
333 static if (__VERSION__
< 2092)
335 final void error(const ref Loc loc
, const(char)* format
, ...)
338 va_start(ap
, format
);
339 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
343 final void error(const(char)* format
, ...)
346 va_start(ap
, format
);
347 const loc
= getLoc();
348 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
352 final void deprecation(const ref Loc loc
, const(char)* format
, ...)
355 va_start(ap
, format
);
356 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
360 final void deprecation(const(char)* format
, ...)
363 va_start(ap
, format
);
364 const loc
= getLoc();
365 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
371 pragma(printf
) final void error(const ref Loc loc
, const(char)* format
, ...)
374 va_start(ap
, format
);
375 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
379 pragma(printf
) final void error(const(char)* format
, ...)
382 va_start(ap
, format
);
383 const loc
= getLoc();
384 .verror(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
388 pragma(printf
) final void deprecation(const ref Loc loc
, const(char)* format
, ...)
391 va_start(ap
, format
);
392 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
396 pragma(printf
) final void deprecation(const(char)* format
, ...)
399 va_start(ap
, format
);
400 const loc
= getLoc();
401 .vdeprecation(loc
, format
, ap
, kind(), prettyFormatHelper().ptr
);
406 final bool checkDeprecated(const ref Loc loc
, Scope
* sc
)
408 if (global
.params
.useDeprecated
== DiagnosticReporting
.off
)
410 if (!this.isDeprecated())
412 // Don't complain if we're inside a deprecated symbol's scope
413 if (sc
.isDeprecated())
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
)
420 const(char)* message
= null;
421 for (Dsymbol p
= this; p
; p
= p
.parent
)
423 message
= p
.depdecl ? p
.depdecl
.getMessage() : null;
428 deprecation(loc
, "is deprecated - %s", message
);
430 deprecation(loc
, "is deprecated");
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
);
440 /**********************************
441 * Determine which Module a Dsymbol is in.
443 final Module
getModule()
445 //printf("Dsymbol::getModule()\n");
446 if (TemplateInstance ti
= isInstantiated())
447 return ti
.tempdecl
.getModule();
451 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
452 Module m
= s
.isModule();
460 /**************************************
461 * Does this Dsymbol come from a C file?
465 final bool isCsymbol()
467 if (Module m
= getModule())
468 return m
.filetype
== FileType
.c
;
472 /**********************************
473 * Determine which Module a Dsymbol is in, as far as access rights go.
475 final Module
getAccessModule()
477 //printf("Dsymbol::getAccessModule()\n");
478 if (TemplateInstance ti
= isInstantiated())
479 return ti
.tempdecl
.getAccessModule();
483 //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
484 Module m
= s
.isModule();
487 TemplateInstance ti
= s
.isTemplateInstance();
488 if (ti
&& ti
.enclosing
)
490 /* Because of local template instantiation, the parent isn't where the access
491 * rights come from - it's the template declaration
502 * `pastMixin` returns the enclosing symbol if this is a template mixin.
504 * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
507 * See also `parent`, `toParent` and `toParent2`.
509 final inout(Dsymbol
) pastMixin() inout
511 //printf("Dsymbol::pastMixin() %s\n", toChars());
512 if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
516 return parent
.pastMixin();
519 /**********************************
520 * `parent` field returns a lexically enclosing scope symbol this is a member of.
522 * `toParent()` returns a logically enclosing scope symbol this is a member of.
523 * It skips over TemplateMixin's.
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.
529 * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
530 * instead of the instantiation scope.
532 * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
533 * if a template declaration is non-local i.e. global or static.
538 * template Foo(alias a) { mixin Bar!(); }
539 * mixin template Bar() {
540 * public { // VisibilityDeclaration
541 * void baz() { a = 2; }
546 * alias foo = Foo!(v);
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')
559 final inout(Dsymbol
) toParent() inout
561 return parent ? parent
.pastMixin() : null;
565 final inout(Dsymbol
) toParent2() inout
567 if (!parent ||
!parent
.isTemplateInstance
&& !parent
.isForwardingAttribDeclaration() && !parent
.isForwardingScopeDsymbol())
569 return parent
.toParent2
;
573 final inout(Dsymbol
) toParentDecl() inout
575 return toParentDeclImpl(false);
579 final inout(Dsymbol
) toParentLocal() inout
581 return toParentDeclImpl(true);
584 private inout(Dsymbol
) toParentDeclImpl(bool localOnly
) inout
587 if (!p ||
!p
.isTemplateInstance())
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
);
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.
600 final Dsymbol
toParentP(Dsymbol p1
, Dsymbol p2
= null)
602 return followInstantiationContext(p1
, p2
) ?
toParent2() : toParentLocal();
605 final inout(TemplateInstance
) isInstantiated() inout
609 auto ti
= parent
.isTemplateInstance();
610 if (ti
&& !ti
.isTemplateMixin())
612 return parent
.isInstantiated();
616 * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
617 * instantiation scope of `this`.
619 final bool followInstantiationContext(Dsymbol p1
, Dsymbol p2
= null)
621 static bool has2This(Dsymbol s
)
623 if (auto f
= s
.isFuncDeclaration())
624 return f
.hasDualContext();
625 if (auto ad
= s
.isAggregateDeclaration())
626 return ad
.vthis2
!is null;
633 auto outer
= toParent();
636 auto ti
= outer
.isTemplateInstance();
639 foreach (oarg
; *ti
.tiargs
)
641 auto sa
= getDsymbol(oarg
);
644 sa
= sa
.toAlias().toParent2();
649 else if (p2
&& sa
== p2
)
652 outer
= ti
.tempdecl
.toParent();
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
667 auto ti
= parent
.isTemplateInstance();
670 if (!parent
.toParent())
672 return parent
.isSpeculative();
675 final Ungag
ungagSpeculative() const
677 uint oldgag
= global
.gag
;
678 if (global
.gag
&& !isSpeculative() && !toParent2().isFuncDeclaration())
680 return Ungag(oldgag
);
683 // kludge for template.isSymbol()
684 override final DYNCAST
dyncast() const
686 return DYNCAST
.dsymbol
;
689 /*************************************
690 * Do syntax copy of an array of Dsymbol's.
692 extern (D
) static Dsymbols
* arraySyntaxCopy(Dsymbols
* a
)
698 for (size_t i
= 0; i
< b
.dim
; i
++)
700 (*b
)[i
] = (*b
)[i
].syntaxCopy(null);
706 Identifier
getIdent()
711 const(char)* toPrettyChars(bool QualifyTypes
= false)
713 if (prettystring
&& !QualifyTypes
)
716 //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
725 // Computer number of components
726 size_t complength
= 0;
727 for (Dsymbol p
= this; p
; p
= p
.parent
)
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
];
735 // Fill in comp[] and compute length of final result
738 for (Dsymbol p
= this; p
; p
= p
.parent
)
740 const s
= QualifyTypes ? p
.toPrettyCharsHelper() : p
.toChars();
741 const len
= strlen(s
);
742 comp
[i
] = s
[0 .. len
];
747 auto s
= cast(char*)mem
.xmalloc_noscan(length
);
748 auto q
= s
+ length
- 1;
750 foreach (j
; 0 .. complength
)
752 const t
= comp
[j
].ptr
;
753 const len
= comp
[j
].length
;
766 const(char)* kind() const pure nothrow @nogc @safe
771 /*********************************
772 * If this symbol is really an alias for another,
774 * If needed, semantic() is invoked due to resolve forward reference.
781 /*********************************
782 * Resolve recursive tuple expansion in eponymous template.
789 void addMember(Scope
* sc
, ScopeDsymbol sds
)
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);
795 if (isAnonymous()) // no name, so can't add it to symbol table
798 if (!sds
.symtabInsert(this)) // if name is already defined
800 if (isAliasDeclaration() && !_scope
)
802 Dsymbol s2
= sds
.symtabLookup(this,ident
);
803 /* https://issues.dlang.org/show_bug.cgi?id=17434
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.
811 if (auto i1
= isImport())
813 if (auto i2
= s2
.isImport())
815 if (sc
.explicitVisibility
&& sc
.visibility
> i2
.visibility
)
816 sds
.symtab
.update(this);
820 // If using C tag/prototype/forward declaration rules
821 if (sc
.flags
& SCOPE
.Cfile
&& !this.isImport())
823 if (handleTagSymbols(*sc
, this, s2
, sds
))
825 if (handleSymbolRedeclarations(*sc
, this, s2
, sds
))
828 sds
.multiplyDefined(Loc
.initial
, this, s2
); // ImportC doesn't allow overloading
833 if (!s2
.overloadInsert(this))
835 sds
.multiplyDefined(Loc
.initial
, this, s2
);
839 if (sds
.isAggregateDeclaration() || sds
.isEnumDeclaration())
841 if (ident
== Id
.__sizeof || ident
== Id
.__xalignof || ident
== Id
._mangleof
)
843 error("`.%s` property cannot be redefined", ident
.toChars());
849 /*************************************
850 * Set scope for future semantic analysis so we can
851 * deal better with forward references.
853 void setScope(Scope
* sc
)
855 //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
857 sc
.setNoFree(); // may need it even after semantic() finishes
860 depdecl
= sc
.depdecl
;
862 userAttribDecl
= sc
.userAttribDecl
;
865 void importAll(Scope
* sc
)
869 /*********************************************
870 * Search for ident as member of s.
872 * loc = location to print for error messages
873 * ident = identifier to search for
878 Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= IgnoreNone
)
880 //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
884 extern (D
) final Dsymbol
search_correct(Identifier ident
)
886 /***************************************************
887 * Search for symbol with correct spelling.
889 extern (D
) Dsymbol
symbol_search_fp(const(char)[] seed
, out int cost
)
891 /* If not in the lexer's string table, it certainly isn't in the symbol table.
892 * Doing this first is a lot faster.
896 Identifier id
= Identifier
.lookup(seed
);
899 cost
= 0; // all the same cost
902 return s
.search(Loc
.initial
, id
, IgnoreErrors
);
906 return null; // don't do it for speculative compiles; too time consuming
907 // search for exact name first
908 if (auto s
= search(Loc
.initial
, ident
, IgnoreErrors
))
910 return speller
!symbol_search_fp(ident
.toString());
913 /***************************************
914 * Search for identifier id as a member of `this`.
915 * `id` may be a template instance.
918 * loc = location to print the error messages
919 * sc = the scope where the symbol is located
920 * id = the id of the symbol
921 * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
924 * symbol found, NULL if not
926 extern (D
) final Dsymbol
searchX(const ref Loc loc
, Scope
* sc
, RootObject id
, int flags
)
928 //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
929 Dsymbol s
= toAlias();
931 if (Declaration d
= s
.isDeclaration())
935 .error(loc
, "circular reference to `%s`", d
.toPrettyChars());
939 switch (id
.dyncast())
941 case DYNCAST
.identifier
:
942 sm
= s
.search(loc
, cast(Identifier
)id
, flags
);
944 case DYNCAST
.dsymbol
:
946 // It's a template instance
947 //printf("\ttemplate instance id\n");
948 Dsymbol st
= cast(Dsymbol
)id
;
949 TemplateInstance ti
= st
.isTemplateInstance();
950 sm
= s
.search(loc
, ti
.name
);
954 TemplateDeclaration td
= sm
.isTemplateDeclaration();
957 .error(loc
, "`%s.%s` is not a template, it is a %s", s
.toPrettyChars(), ti
.name
.toChars(), sm
.kind());
962 ti
.dsymbolSemantic(sc
);
967 case DYNCAST
.expression
:
974 bool overloadInsert(Dsymbol s
)
976 //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
980 /*********************************
982 * SIZE_INVALID when the size cannot be determined
984 uinteger_t
size(const ref Loc loc
)
986 error("Dsymbol `%s` has no size", toChars());
995 // is a 'this' required to access the member
996 inout(AggregateDeclaration
) isThis() inout
1001 // is Dsymbol exported?
1002 bool isExport() const
1007 // is Dsymbol imported?
1008 bool isImportedSymbol() const
1013 // is Dsymbol deprecated?
1014 bool isDeprecated() @safe @nogc pure nothrow const
1019 bool isOverloadable() const
1024 // is this a LabelDsymbol()?
1025 LabelDsymbol
isLabel()
1030 /// Returns an AggregateDeclaration when toParent() is that.
1031 final inout(AggregateDeclaration
) isMember() inout
1033 //printf("Dsymbol::isMember() %s\n", toChars());
1034 auto p
= toParent();
1035 //printf("parent is %s %s\n", p.kind(), p.toChars());
1036 return p ? p
.isAggregateDeclaration() : null;
1039 /// Returns an AggregateDeclaration when toParent2() is that.
1040 final inout(AggregateDeclaration
) isMember2() inout
1042 //printf("Dsymbol::isMember2() '%s'\n", toChars());
1043 auto p
= toParent2();
1044 //printf("parent is %s %s\n", p.kind(), p.toChars());
1045 return p ? p
.isAggregateDeclaration() : null;
1048 /// Returns an AggregateDeclaration when toParentDecl() is that.
1049 final inout(AggregateDeclaration
) isMemberDecl() inout
1051 //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
1052 auto p
= toParentDecl();
1053 //printf("parent is %s %s\n", p.kind(), p.toChars());
1054 return p ? p
.isAggregateDeclaration() : null;
1057 /// Returns an AggregateDeclaration when toParentLocal() is that.
1058 final inout(AggregateDeclaration
) isMemberLocal() inout
1060 //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
1061 auto p
= toParentLocal();
1062 //printf("parent is %s %s\n", p.kind(), p.toChars());
1063 return p ? p
.isAggregateDeclaration() : null;
1066 // is this a member of a ClassDeclaration?
1067 final ClassDeclaration
isClassMember()
1069 auto ad
= isMember();
1070 return ad ? ad
.isClassDeclaration() : null;
1079 // need a 'this' pointer?
1085 /*************************************
1087 Visibility
visible() pure nothrow @nogc @safe
1089 return Visibility(Visibility
.Kind
.public_
);
1092 /**************************************
1094 * Used for template instantiations.
1095 * If s is NULL, allocate the new object, otherwise fill it in.
1097 Dsymbol
syntaxCopy(Dsymbol s
)
1099 printf("%s %s\n", kind(), toChars());
1103 /**************************************
1104 * Determine if this symbol is only one.
1106 * false, *ps = NULL: There are 2 or more symbols
1107 * true, *ps = NULL: There are zero symbols
1108 * true, *ps = symbol: The one and only one symbol
1110 bool oneMember(Dsymbol
* ps
, Identifier ident
)
1112 //printf("Dsymbol::oneMember()\n");
1117 /*****************************************
1118 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1120 extern (D
) static bool oneMembers(Dsymbols
* members
, Dsymbol
* ps
, Identifier ident
)
1122 //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1130 for (size_t i
= 0; i
< members
.dim
; i
++)
1132 Dsymbol sx
= (*members
)[i
];
1133 bool x
= sx
.oneMember(ps
, ident
);
1134 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1137 //printf("\tfalse 1\n");
1138 assert(*ps
is null);
1144 if (!(*ps
).ident ||
!(*ps
).ident
.equals(ident
))
1148 else if (s
.isOverloadable() && (*ps
).isOverloadable())
1150 // keep head of overload set
1151 FuncDeclaration f1
= s
.isFuncDeclaration();
1152 FuncDeclaration f2
= (*ps
).isFuncDeclaration();
1155 assert(!f1
.isFuncAliasDeclaration());
1156 assert(!f2
.isFuncAliasDeclaration());
1157 for (; f1
!= f2
; f1
= f1
.overnext0
)
1159 if (f1
.overnext0
is null)
1167 else // more than one symbol
1170 //printf("\tfalse 2\n");
1175 *ps
= s
; // s is the one symbol, null if none
1176 //printf("\ttrue\n");
1180 void setFieldOffset(AggregateDeclaration ad
, ref FieldState fieldState
, bool isunion
)
1184 /*****************************************
1185 * Is Dsymbol a variable that contains pointers?
1189 //printf("Dsymbol::hasPointers() %s\n", toChars());
1193 bool hasStaticCtorOrDtor()
1195 //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1199 void addLocalClass(ClassDeclarations
*)
1203 void addObjcSymbols(ClassDeclarations
* classes
, ClassDeclarations
* categories
)
1207 void checkCtorConstInit()
1211 /****************************************
1212 * Add documentation comment to Dsymbol.
1213 * Ignore NULL comments.
1215 void addComment(const(char)* comment
)
1217 if (!comment ||
!*comment
)
1220 //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
1221 void* h
= cast(void*)this; // just the pointer is the key
1222 auto p
= h
in commentHashTable
;
1225 commentHashTable
[h
] = comment
;
1228 if (strcmp(*p
, comment
) != 0)
1230 // Concatenate the two
1231 *p
= Lexer
.combineComments((*p
).toDString(), comment
.toDString(), true);
1235 /// get documentation comment for this Dsymbol
1236 final const(char)* comment()
1238 //printf("getcomment: %p '%s'\n", this, this.toChars());
1239 if (auto p
= cast(void*)this in commentHashTable
)
1241 //printf("comment: '%s'\n", *p);
1247 /* Shell around addComment() to avoid disruption for the moment */
1248 final void comment(const(char)* comment
) { addComment(comment
); }
1250 private extern (D
) __gshared
const(char)*[void*] commentHashTable
;
1253 /**********************************
1254 * Get ddoc unittest associated with this symbol.
1255 * (only use this with ddoc)
1256 * Returns: ddoc unittest, null if none
1258 final UnitTestDeclaration
ddocUnittest()
1260 if (auto p
= cast(void*)this in ddocUnittestHashTable
)
1265 /**********************************
1266 * Set ddoc unittest associated with this symbol.
1268 final void ddocUnittest(UnitTestDeclaration utd
)
1270 ddocUnittestHashTable
[cast(void*)this] = utd
;
1273 private extern (D
) __gshared UnitTestDeclaration
[void*] ddocUnittestHashTable
;
1276 /****************************************
1277 * Returns true if this symbol is defined in a non-root module without instantiation.
1279 final bool inNonRoot()
1282 for (; s
; s
= s
.toParent())
1284 if (auto ti
= s
.isTemplateInstance())
1288 if (auto m
= s
.isModule())
1299 * Deinitializes the global state of the compiler.
1301 * This can be used to restore the state set by `_init` to its original
1304 static void deinitialize()
1306 commentHashTable
= commentHashTable
.init
;
1307 ddocUnittestHashTable
= ddocUnittestHashTable
.init
;
1312 override void accept(Visitor v
)
1317 pure nothrow @safe @nogc:
1319 // Eliminate need for dynamic_cast
1320 inout(Package
) isPackage() inout { return null; }
1321 inout(Module
) isModule() inout { return null; }
1322 inout(EnumMember
) isEnumMember() inout { return null; }
1323 inout(TemplateDeclaration
) isTemplateDeclaration() inout { return null; }
1324 inout(TemplateInstance
) isTemplateInstance() inout { return null; }
1325 inout(TemplateMixin
) isTemplateMixin() inout { return null; }
1326 inout(ForwardingAttribDeclaration
) isForwardingAttribDeclaration() inout { return null; }
1327 inout(Nspace
) isNspace() inout { return null; }
1328 inout(Declaration
) isDeclaration() inout { return null; }
1329 inout(StorageClassDeclaration
) isStorageClassDeclaration() inout { return null; }
1330 inout(ExpressionDsymbol
) isExpressionDsymbol() inout { return null; }
1331 inout(AliasAssign
) isAliasAssign() inout { return null; }
1332 inout(ThisDeclaration
) isThisDeclaration() inout { return null; }
1333 inout(BitFieldDeclaration
) isBitFieldDeclaration() inout { return null; }
1334 inout(TypeInfoDeclaration
) isTypeInfoDeclaration() inout { return null; }
1335 inout(TupleDeclaration
) isTupleDeclaration() inout { return null; }
1336 inout(AliasDeclaration
) isAliasDeclaration() inout { return null; }
1337 inout(AggregateDeclaration
) isAggregateDeclaration() inout { return null; }
1338 inout(FuncDeclaration
) isFuncDeclaration() inout { return null; }
1339 inout(FuncAliasDeclaration
) isFuncAliasDeclaration() inout { return null; }
1340 inout(OverDeclaration
) isOverDeclaration() inout { return null; }
1341 inout(FuncLiteralDeclaration
) isFuncLiteralDeclaration() inout { return null; }
1342 inout(CtorDeclaration
) isCtorDeclaration() inout { return null; }
1343 inout(PostBlitDeclaration
) isPostBlitDeclaration() inout { return null; }
1344 inout(DtorDeclaration
) isDtorDeclaration() inout { return null; }
1345 inout(StaticCtorDeclaration
) isStaticCtorDeclaration() inout { return null; }
1346 inout(StaticDtorDeclaration
) isStaticDtorDeclaration() inout { return null; }
1347 inout(SharedStaticCtorDeclaration
) isSharedStaticCtorDeclaration() inout { return null; }
1348 inout(SharedStaticDtorDeclaration
) isSharedStaticDtorDeclaration() inout { return null; }
1349 inout(InvariantDeclaration
) isInvariantDeclaration() inout { return null; }
1350 inout(UnitTestDeclaration
) isUnitTestDeclaration() inout { return null; }
1351 inout(NewDeclaration
) isNewDeclaration() inout { return null; }
1352 inout(VarDeclaration
) isVarDeclaration() inout { return null; }
1353 inout(VersionSymbol
) isVersionSymbol() inout { return null; }
1354 inout(DebugSymbol
) isDebugSymbol() inout { return null; }
1355 inout(ClassDeclaration
) isClassDeclaration() inout { return null; }
1356 inout(StructDeclaration
) isStructDeclaration() inout { return null; }
1357 inout(UnionDeclaration
) isUnionDeclaration() inout { return null; }
1358 inout(InterfaceDeclaration
) isInterfaceDeclaration() inout { return null; }
1359 inout(ScopeDsymbol
) isScopeDsymbol() inout { return null; }
1360 inout(ForwardingScopeDsymbol
) isForwardingScopeDsymbol() inout { return null; }
1361 inout(WithScopeSymbol
) isWithScopeSymbol() inout { return null; }
1362 inout(ArrayScopeSymbol
) isArrayScopeSymbol() inout { return null; }
1363 inout(Import
) isImport() inout { return null; }
1364 inout(EnumDeclaration
) isEnumDeclaration() inout { return null; }
1365 inout(SymbolDeclaration
) isSymbolDeclaration() inout { return null; }
1366 inout(AttribDeclaration
) isAttribDeclaration() inout { return null; }
1367 inout(AnonDeclaration
) isAnonDeclaration() inout { return null; }
1368 inout(CPPNamespaceDeclaration
) isCPPNamespaceDeclaration() inout { return null; }
1369 inout(VisibilityDeclaration
) isVisibilityDeclaration() inout { return null; }
1370 inout(OverloadSet
) isOverloadSet() inout { return null; }
1371 inout(CompileDeclaration
) isCompileDeclaration() inout { return null; }
1372 inout(StaticAssert
) isStaticAssert() inout { return null; }
1375 /***********************************************************
1376 * Dsymbol that generates a scope
1378 extern (C
++) class ScopeDsymbol
: Dsymbol
1380 Dsymbols
* members
; // all Dsymbol's in this scope
1381 DsymbolTable symtab
; // members[] sorted into table
1382 uint endlinnum
; // the linnumber of the statement after the scope (0 if unknown)
1385 /// symbols whose members have been imported, i.e. imported modules and template mixins
1386 Dsymbols
* importedScopes
;
1387 Visibility
.Kind
* visibilities
; // array of Visibility.Kind, one for each import
1389 import dmd
.root
.bitarray
;
1390 BitArray accessiblePackages
, privateAccessiblePackages
;// whitelists of accessible (imported) packages
1393 final extern (D
) this() nothrow
1397 final extern (D
) this(Identifier ident
) nothrow
1402 final extern (D
) this(const ref Loc loc
, Identifier ident
) nothrow
1407 override ScopeDsymbol
syntaxCopy(Dsymbol s
)
1409 //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1410 ScopeDsymbol sds
= s ?
cast(ScopeDsymbol
)s
: new ScopeDsymbol(ident
);
1411 sds
.comment
= comment
;
1412 sds
.members
= arraySyntaxCopy(members
);
1413 sds
.endlinnum
= endlinnum
;
1417 /*****************************************
1418 * This function is #1 on the list of functions that eat cpu time.
1419 * Be very, very careful about slowing it down.
1421 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= SearchLocalsOnly
)
1423 //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1424 //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1426 // Look in symbols declared in this module
1427 if (symtab
&& !(flags
& SearchImportsOnly
))
1429 //printf(" look in locals\n");
1430 auto s1
= symtab
.lookup(ident
);
1433 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1437 //printf(" not found in locals\n");
1439 // Look in imported scopes
1440 if (!importedScopes
)
1443 //printf(" look in imports\n");
1445 OverloadSet a
= null;
1446 // Look in imported modules
1447 for (size_t i
= 0; i
< importedScopes
.dim
; i
++)
1449 // If private import, don't search it
1450 if ((flags
& IgnorePrivateImports
) && visibilities
[i
] == Visibility
.Kind
.private_
)
1452 int sflags
= flags
& (IgnoreErrors | IgnoreAmbiguous
); // remember these in recursive searches
1453 Dsymbol ss
= (*importedScopes
)[i
];
1454 //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
1458 if (flags
& SearchLocalsOnly
)
1461 else // mixin template
1463 if (flags
& SearchImportsOnly
)
1466 sflags |
= SearchLocalsOnly
;
1469 /* Don't find private members if ss is a module
1471 Dsymbol s2
= ss
.search(loc
, ident
, sflags |
(ss
.isModule() ? IgnorePrivateImports
: IgnoreNone
));
1472 import dmd
.access
: symbolIsVisible
;
1473 if (!s2 ||
!(flags
& IgnoreSymbolVisibility
) && !symbolIsVisible(this, s2
))
1478 if (s
&& s
.isOverloadSet())
1479 a
= mergeOverloadSet(ident
, a
, s
);
1481 else if (s2
&& s
!= s2
)
1483 if (s
.toAlias() == s2
.toAlias() || s
.getType() == s2
.getType() && s
.getType())
1485 /* After following aliases, we found the same
1486 * symbol, so it's not an ambiguity. But if one
1487 * alias is deprecated or less accessible, prefer
1490 if (s
.isDeprecated() || s
.visible() < s2
.visible() && s2
.visible().kind
!= Visibility
.Kind
.none
)
1495 /* Two imports of the same module should be regarded as
1498 Import i1
= s
.isImport();
1499 Import i2
= s2
.isImport();
1500 if (!(i1
&& i2
&& (i1
.mod
== i2
.mod ||
(!i1
.parent
.isImport() && !i2
.parent
.isImport() && i1
.ident
.equals(i2
.ident
)))))
1502 /* https://issues.dlang.org/show_bug.cgi?id=8668
1503 * Public selective import adds AliasDeclaration in module.
1504 * To make an overload set, resolve aliases in here and
1505 * get actual overload roots which accessible via s and s2.
1509 /* If both s2 and s are overloadable (though we only
1510 * need to check s once)
1513 auto so2
= s2
.isOverloadSet();
1514 if ((so2 || s2
.isOverloadable()) && (a || s
.isOverloadable()))
1516 if (symbolIsVisible(this, s2
))
1518 a
= mergeOverloadSet(ident
, a
, s2
);
1520 if (!symbolIsVisible(this, s
))
1525 /* Two different overflow sets can have the same members
1526 * https://issues.dlang.org/show_bug.cgi?id=16709
1528 auto so
= s
.isOverloadSet();
1531 if (so
.a
.length
== so2
.a
.length
)
1533 foreach (j
; 0 .. so
.a
.length
)
1535 if (so
.a
[j
] !is so2
.a
[j
])
1538 continue; // the same
1544 if (flags
& IgnoreAmbiguous
) // if return NULL on ambiguity
1546 if (!(flags
& IgnoreErrors
))
1547 ScopeDsymbol
.multiplyDefined(loc
, s
, s2
);
1555 /* Build special symbol if we had multiple finds
1559 if (!s
.isOverloadSet())
1560 a
= mergeOverloadSet(ident
, a
, s
);
1563 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1566 //printf(" not found in imports\n");
1570 extern (D
) private OverloadSet
mergeOverloadSet(Identifier ident
, OverloadSet os
, Dsymbol s
)
1574 os
= new OverloadSet(ident
);
1577 if (OverloadSet os2
= s
.isOverloadSet())
1579 // Merge the cross-module overload set 'os2' into 'os'
1582 os
.a
.setDim(os2
.a
.dim
);
1583 memcpy(os
.a
.tdata(), os2
.a
.tdata(), (os
.a
[0]).sizeof
* os2
.a
.dim
);
1587 for (size_t i
= 0; i
< os2
.a
.dim
; i
++)
1589 os
= mergeOverloadSet(ident
, os
, os2
.a
[i
]);
1595 assert(s
.isOverloadable());
1596 /* Don't add to os[] if s is alias of previous sym
1598 for (size_t j
= 0; j
< os
.a
.dim
; j
++)
1600 Dsymbol s2
= os
.a
[j
];
1601 if (s
.toAlias() == s2
.toAlias())
1603 if (s2
.isDeprecated() ||
(s2
.visible() < s
.visible() && s
.visible().kind
!= Visibility
.Kind
.none
))
1616 void importScope(Dsymbol s
, Visibility visibility
) nothrow
1618 //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
1619 // No circular or redundant import's
1622 if (!importedScopes
)
1623 importedScopes
= new Dsymbols();
1626 for (size_t i
= 0; i
< importedScopes
.dim
; i
++)
1628 Dsymbol ss
= (*importedScopes
)[i
];
1629 if (ss
== s
) // if already imported
1631 if (visibility
.kind
> visibilities
[i
])
1632 visibilities
[i
] = visibility
.kind
; // upgrade access
1637 importedScopes
.push(s
);
1638 visibilities
= cast(Visibility
.Kind
*)mem
.xrealloc(visibilities
, importedScopes
.dim
* (visibilities
[0]).sizeof
);
1639 visibilities
[importedScopes
.dim
- 1] = visibility
.kind
;
1643 extern (D
) final void addAccessiblePackage(Package p
, Visibility visibility
) nothrow
1645 auto pary
= visibility
.kind
== Visibility
.Kind
.private_ ?
&privateAccessiblePackages
: &accessiblePackages
;
1646 if (pary
.length
<= p
.tag
)
1647 pary
.length
= p
.tag
+ 1;
1648 (*pary
)[p
.tag
] = true;
1651 bool isPackageAccessible(Package p
, Visibility visibility
, int flags
= 0) nothrow
1653 if (p
.tag
< accessiblePackages
.length
&& accessiblePackages
[p
.tag
] ||
1654 visibility
.kind
== Visibility
.Kind
.private_
&& p
.tag
< privateAccessiblePackages
.length
&& privateAccessiblePackages
[p
.tag
])
1656 foreach (i
, ss
; importedScopes ?
(*importedScopes
)[] : null)
1658 // only search visible scopes && imported modules should ignore private imports
1659 if (visibility
.kind
<= visibilities
[i
] &&
1660 ss
.isScopeDsymbol
.isPackageAccessible(p
, visibility
, IgnorePrivateImports
))
1666 override final bool isforwardRef() nothrow
1668 return (members
is null);
1671 static void multiplyDefined(const ref Loc loc
, Dsymbol s1
, Dsymbol s2
)
1675 printf("ScopeDsymbol::multiplyDefined()\n");
1676 printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1
, s1
.toChars(), s1
.kind(), s1
.parent ? s1
.parent
.toChars() : "");
1677 printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2
, s2
.toChars(), s2
.kind(), s2
.parent ? s2
.parent
.toChars() : "");
1681 .error(loc
, "%s `%s` at %s conflicts with %s `%s` at %s",
1682 s1
.kind(), s1
.toPrettyChars(), s1
.locToChars(),
1683 s2
.kind(), s2
.toPrettyChars(), s2
.locToChars());
1687 if (auto so
= s1
.isOverloadSet())
1689 printf("first %p:\n", so
);
1692 printf(" %p %s `%s` at %s\n", s
, s
.kind(), s
.toPrettyChars(), s
.locToChars());
1695 if (auto so
= s2
.isOverloadSet())
1697 printf("second %p:\n", so
);
1700 printf(" %p %s `%s` at %s\n", s
, s
.kind(), s
.toPrettyChars(), s
.locToChars());
1707 s1
.error(s1
.loc
, "conflicts with %s `%s` at %s", s2
.kind(), s2
.toPrettyChars(), s2
.locToChars());
1711 override const(char)* kind() const
1713 return "ScopeDsymbol";
1716 /*******************************************
1717 * Look for member of the form:
1718 * const(MemberInfo)[] getMembers(string);
1719 * Returns NULL if not found
1721 final FuncDeclaration
findGetMembers()
1723 Dsymbol s
= search_function(this, Id
.getmembers
);
1724 FuncDeclaration fdx
= s ? s
.isFuncDeclaration() : null;
1728 __gshared TypeFunction tfgetmembers
;
1732 auto parameters
= new Parameters();
1733 Parameters
* p
= new Parameter(STC
.in_
, Type
.tchar
.constOf().arrayOf(), null, null);
1736 tfgetmembers
= new TypeFunction(parameters
, tret
, VarArg
.none
, LINK
.d
);
1737 tfgetmembers
= cast(TypeFunction
)tfgetmembers
.dsymbolSemantic(Loc
.initial
, &sc
);
1740 fdx
= fdx
.overloadExactMatch(tfgetmembers
);
1742 if (fdx
&& fdx
.isVirtual())
1747 /********************************
1748 * Insert Dsymbol in table.
1752 * null if already in table, `s` if inserted
1754 Dsymbol
symtabInsert(Dsymbol s
) nothrow
1756 return symtab
.insert(s
);
1759 /****************************************
1760 * Look up identifier in symbol table.
1763 * id = identifier to look up
1765 * Dsymbol if found, null if not
1767 Dsymbol
symtabLookup(Dsymbol s
, Identifier id
) nothrow
1769 return symtab
.lookup(id
);
1772 /****************************************
1773 * Return true if any of the members are static ctors or static dtors, or if
1774 * any members have members that are.
1776 override bool hasStaticCtorOrDtor()
1780 for (size_t i
= 0; i
< members
.dim
; i
++)
1782 Dsymbol member
= (*members
)[i
];
1783 if (member
.hasStaticCtorOrDtor())
1790 extern (D
) alias ForeachDg
= int delegate(size_t idx
, Dsymbol s
);
1792 /***************************************
1793 * Expands attribute declarations in members in depth first
1794 * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1796 * If dg returns !=0, stops and returns that value else returns 0.
1797 * Use this function to avoid the O(N + N^2/2) complexity of
1798 * calculating dim and calling N times getNth.
1800 * last value returned by dg()
1802 extern (D
) static int _foreach(Scope
* sc
, Dsymbols
* members
, scope ForeachDg dg
, size_t
* pn
= null)
1807 size_t n
= pn ?
*pn
: 0; // take over index
1809 foreach (size_t i
; 0 .. members
.dim
)
1811 Dsymbol s
= (*members
)[i
];
1812 if (AttribDeclaration a
= s
.isAttribDeclaration())
1813 result
= _foreach(sc
, a
.include(sc
), dg
, &n
);
1814 else if (TemplateMixin tm
= s
.isTemplateMixin())
1815 result
= _foreach(sc
, tm
.members
, dg
, &n
);
1816 else if (s
.isTemplateInstance())
1819 else if (s
.isUnitTestDeclaration())
1823 result
= dg(n
++, s
);
1828 *pn
= n
; // update index
1832 override final inout(ScopeDsymbol
) isScopeDsymbol() inout
1837 override void accept(Visitor v
)
1843 /***********************************************************
1844 * With statement scope
1846 extern (C
++) final class WithScopeSymbol
: ScopeDsymbol
1848 WithStatement withstate
;
1850 extern (D
) this(WithStatement withstate
) nothrow
1852 this.withstate
= withstate
;
1855 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= SearchLocalsOnly
)
1857 //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1858 if (flags
& SearchImportsOnly
)
1860 // Acts as proxy to the with class declaration
1862 Expression eold
= null;
1863 for (Expression e
= withstate
.exp
; e
&& e
!= eold
; e
= resolveAliasThis(_scope
, e
, true))
1865 if (e
.op
== EXP
.scope_
)
1867 s
= (cast(ScopeExp
)e
).sds
;
1869 else if (e
.op
== EXP
.type
)
1871 s
= e
.type
.toDsymbol(null);
1875 Type t
= e
.type
.toBasetype();
1876 s
= t
.toDsymbol(null);
1880 s
= s
.search(loc
, ident
, flags
);
1889 override inout(WithScopeSymbol
) isWithScopeSymbol() inout
1894 override void accept(Visitor v
)
1900 /***********************************************************
1901 * Array Index/Slice scope
1903 extern (C
++) final class ArrayScopeSymbol
: ScopeDsymbol
1905 // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1906 // Discriminated using DYNCAST and, for expressions, also EXP
1907 private RootObject arrayContent
;
1910 extern (D
) this(Scope
* sc
, Expression exp
) nothrow
1912 super(exp
.loc
, null);
1913 assert(exp
.op
== EXP
.index || exp
.op
== EXP
.slice || exp
.op
== EXP
.array
);
1915 this.arrayContent
= exp
;
1918 extern (D
) this(Scope
* sc
, TypeTuple type
) nothrow
1921 this.arrayContent
= type
;
1924 extern (D
) this(Scope
* sc
, TupleDeclaration td
) nothrow
1927 this.arrayContent
= td
;
1930 /// This override is used to solve `$`
1931 override Dsymbol
search(const ref Loc loc
, Identifier ident
, int flags
= IgnoreNone
)
1933 //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1934 if (ident
!= Id
.dollar
)
1937 VarDeclaration
* pvar
;
1940 static Dsymbol
dollarFromTypeTuple(const ref Loc loc
, TypeTuple tt
, Scope
* sc
)
1943 /* $ gives the number of type entries in the type tuple
1945 auto v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, null);
1946 Expression e
= new IntegerExp(Loc
.initial
, tt
.arguments
.dim
, Type
.tsize_t
);
1947 v
._init
= new ExpInitializer(Loc
.initial
, e
);
1948 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
1949 v
.dsymbolSemantic(sc
);
1953 const DYNCAST kind
= arrayContent
.dyncast();
1954 if (kind
== DYNCAST
.dsymbol
)
1956 TupleDeclaration td
= cast(TupleDeclaration
) arrayContent
;
1957 /* $ gives the number of elements in the tuple
1959 auto v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, null);
1960 Expression e
= new IntegerExp(Loc
.initial
, td
.objects
.dim
, Type
.tsize_t
);
1961 v
._init
= new ExpInitializer(Loc
.initial
, e
);
1962 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
1963 v
.dsymbolSemantic(sc
);
1966 if (kind
== DYNCAST
.type
)
1968 return dollarFromTypeTuple(loc
, cast(TypeTuple
) arrayContent
, sc
);
1970 Expression exp
= cast(Expression
) arrayContent
;
1971 if (auto ie
= exp
.isIndexExp())
1973 /* array[index] where index is some function of $
1975 pvar
= &ie
.lengthVar
;
1978 else if (auto se
= exp
.isSliceExp())
1980 /* array[lwr .. upr] where lwr or upr is some function of $
1982 pvar
= &se
.lengthVar
;
1985 else if (auto ae
= exp
.isArrayExp())
1987 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1988 * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1990 pvar
= &ae
.lengthVar
;
1995 /* Didn't find $, look in enclosing scope(s).
1999 ce
= ce
.lastComma();
2000 /* If we are indexing into an array that is really a type
2001 * tuple, rewrite this as an index into a type tuple and
2004 if (auto te
= ce
.isTypeExp())
2006 if (auto ttp
= te
.type
.isTypeTuple())
2007 return dollarFromTypeTuple(loc
, ttp
, sc
);
2009 /* *pvar is lazily initialized, so if we refer to $
2010 * multiple times, it gets set only once.
2012 if (!*pvar
) // if not already initialized
2014 /* Create variable v and set it to the value of $
2018 if (auto tupexp
= ce
.isTupleExp())
2020 /* It is for an expression tuple, so the
2021 * length will be a const.
2023 Expression e
= new IntegerExp(Loc
.initial
, tupexp
.exps
.dim
, Type
.tsize_t
);
2024 v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, new ExpInitializer(Loc
.initial
, e
));
2025 v
.storage_class |
= STC
.temp | STC
.static_ | STC
.const_
;
2027 else if (ce
.type
&& (t
= ce
.type
.toBasetype()) !is null && (t
.ty
== Tstruct || t
.ty
== Tclass
))
2029 // Look for opDollar
2030 assert(exp
.op
== EXP
.array || exp
.op
== EXP
.slice
);
2031 AggregateDeclaration ad
= isAggregate(t
);
2033 Dsymbol s
= ad
.search(loc
, Id
.opDollar
);
2034 if (!s
) // no dollar exists -- search in higher scope
2037 Expression e
= null;
2038 // Check for multi-dimensional opDollar(dim) template.
2039 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
2042 if (exp
.op
== EXP
.array
)
2044 dim
= (cast(ArrayExp
)exp
).currentDimension
;
2046 else if (exp
.op
== EXP
.slice
)
2048 dim
= 0; // slices are currently always one-dimensional
2054 auto tiargs
= new Objects();
2055 Expression edim
= new IntegerExp(Loc
.initial
, dim
, Type
.tsize_t
);
2056 edim
= edim
.expressionSemantic(sc
);
2058 e
= new DotTemplateInstanceExp(loc
, ce
, td
.ident
, tiargs
);
2062 /* opDollar exists, but it's not a template.
2063 * This is acceptable ONLY for single-dimension indexing.
2064 * Note that it's impossible to have both template & function opDollar,
2065 * because both take no arguments.
2067 if (exp
.op
== EXP
.array
&& (cast(ArrayExp
)exp
).arguments
.dim
!= 1)
2069 exp
.error("`%s` only defines opDollar for one dimension", ad
.toChars());
2072 Declaration d
= s
.isDeclaration();
2074 e
= new DotVarExp(loc
, ce
, d
);
2076 e
= e
.expressionSemantic(sc
);
2078 exp
.error("`%s` has no value", e
.toChars());
2079 t
= e
.type
.toBasetype();
2080 if (t
&& t
.ty
== Tfunction
)
2081 e
= new CallExp(e
.loc
, e
);
2082 v
= new VarDeclaration(loc
, null, Id
.dollar
, new ExpInitializer(Loc
.initial
, e
));
2083 v
.storage_class |
= STC
.temp | STC
.ctfe | STC
.rvalue
;
2087 /* For arrays, $ will either be a compile-time constant
2088 * (in which case its value in set during constant-folding),
2089 * or a variable (in which case an expression is created in
2092 auto e
= new VoidInitializer(Loc
.initial
);
2093 e
.type
= Type
.tsize_t
;
2094 v
= new VarDeclaration(loc
, Type
.tsize_t
, Id
.dollar
, e
);
2095 v
.storage_class |
= STC
.temp | STC
.ctfe
; // it's never a true static variable
2099 (*pvar
).dsymbolSemantic(sc
);
2103 override inout(ArrayScopeSymbol
) isArrayScopeSymbol() inout
2108 override void accept(Visitor v
)
2114 /***********************************************************
2117 extern (C
++) final class OverloadSet
: Dsymbol
2119 Dsymbols a
; // array of Dsymbols
2121 extern (D
) this(Identifier ident
, OverloadSet os
= null) nothrow
2126 a
.pushSlice(os
.a
[]);
2130 void push(Dsymbol s
) nothrow
2135 override inout(OverloadSet
) isOverloadSet() inout
2140 override const(char)* kind() const
2142 return "overloadset";
2145 override void accept(Visitor v
)
2151 /***********************************************************
2152 * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
2153 * ForwardingScopeDeclaration to forward symbol insertions to another
2154 * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
2157 extern (C
++) final class ForwardingScopeDsymbol
: ScopeDsymbol
2159 /*************************
2160 * Symbol to forward insertions to.
2161 * Can be `null` before being lazily initialized.
2163 ScopeDsymbol forward
;
2164 extern (D
) this(ScopeDsymbol forward
) nothrow
2167 this.forward
= forward
;
2170 override Dsymbol
symtabInsert(Dsymbol s
) nothrow
2173 if (auto d
= s
.isDeclaration())
2175 if (d
.storage_class
& STC
.local
)
2177 // Symbols with storage class STC.local are not
2178 // forwarded, but stored in the local symbol
2179 // table. (Those are the `static foreach` variables.)
2182 symtab
= new DsymbolTable();
2184 return super.symtabInsert(s
); // insert locally
2187 if (!forward
.symtab
)
2189 forward
.symtab
= new DsymbolTable();
2191 // Non-STC.local symbols are forwarded to `forward`.
2192 return forward
.symtabInsert(s
);
2195 /************************
2196 * This override handles the following two cases:
2197 * static foreach (i, i; [0]) { ... }
2199 * static foreach (i; [0]) { enum i = 2; }
2201 override Dsymbol
symtabLookup(Dsymbol s
, Identifier id
) nothrow
2204 // correctly diagnose clashing foreach loop variables.
2205 if (auto d
= s
.isDeclaration())
2207 if (d
.storage_class
& STC
.local
)
2211 symtab
= new DsymbolTable();
2213 return super.symtabLookup(s
,id
);
2216 // Declarations within `static foreach` do not clash with
2217 // `static foreach` loop variables.
2218 if (!forward
.symtab
)
2220 forward
.symtab
= new DsymbolTable();
2222 return forward
.symtabLookup(s
,id
);
2225 override void importScope(Dsymbol s
, Visibility visibility
)
2227 forward
.importScope(s
, visibility
);
2230 override const(char)* kind()const{ return "local scope"; }
2232 override inout(ForwardingScopeDsymbol
) isForwardingScopeDsymbol() inout nothrow
2240 * Class that holds an expression in a Dsymbol wrapper.
2241 * This is not an AST node, but a class used to pass
2242 * an expression as a function parameter of type Dsymbol.
2244 extern (C
++) final class ExpressionDsymbol
: Dsymbol
2247 this(Expression exp
) nothrow
2253 override inout(ExpressionDsymbol
) isExpressionDsymbol() inout nothrow
2259 /**********************************************
2260 * Encapsulate assigning to an alias:
2261 * `identifier = type;`
2262 * `identifier = symbol;`
2263 * where `identifier` is an AliasDeclaration in scope.
2265 extern (C
++) final class AliasAssign
: Dsymbol
2267 Identifier ident
; /// Dsymbol's ident will be null, as this class is anonymous
2268 Type type
; /// replace previous RHS of AliasDeclaration with `type`
2269 Dsymbol aliassym
; /// replace previous RHS of AliasDeclaration with `aliassym`
2270 /// only one of type and aliassym can be != null
2272 extern (D
) this(const ref Loc loc
, Identifier ident
, Type type
, Dsymbol aliassym
) nothrow
2277 this.aliassym
= aliassym
;
2280 override AliasAssign
syntaxCopy(Dsymbol s
)
2283 AliasAssign aa
= new AliasAssign(loc
, ident
,
2284 type ? type
.syntaxCopy() : null,
2285 aliassym ? aliassym
.syntaxCopy(null) : null);
2289 override inout(AliasAssign
) isAliasAssign() inout
2294 override const(char)* kind() const
2296 return "alias assignment";
2299 override void accept(Visitor v
)
2305 /***********************************************************
2306 * Table of Dsymbol's
2308 extern (C
++) final class DsymbolTable
: RootObject
2310 AssocArray
!(Identifier
, Dsymbol
) tab
;
2314 /***************************
2315 * Look up Identifier in symbol table
2317 * ident = identifer to look up
2319 * Dsymbol if found, null if not
2321 Dsymbol
lookup(const Identifier ident
)
2323 //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2328 * Replace existing symbol in symbol table with `s`.
2329 * If it's not there, add it.
2331 * s = replacement symbol with same identifier
2333 void update(Dsymbol s
)
2335 *tab
.getLvalue(s
.ident
) = s
;
2338 /**************************
2339 * Insert Dsymbol in table.
2343 * null if already in table, `s` if inserted
2345 Dsymbol
insert(Dsymbol s
)
2347 return insert(s
.ident
, s
);
2350 /**************************
2351 * Insert Dsymbol in table.
2353 * ident = identifier to serve as index
2356 * null if already in table, `s` if inserted
2358 Dsymbol
insert(const Identifier ident
, Dsymbol s
)
2360 //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
2361 Dsymbol
* ps
= tab
.getLvalue(ident
);
2363 return null; // already in table
2370 * number of symbols in symbol table
2372 size_t
length() const pure
2378 /**********************************************
2379 * ImportC tag symbols sit in a parallel symbol table,
2380 * so that this C code works:
2386 * But there are relatively few such tag symbols, so that would be
2387 * a waste of memory and complexity. An additional problem is we'd like the D side
2388 * to find the tag symbols with ordinary lookup, not lookup in both
2389 * tables, if the tag symbol is not conflicting with an ordinary symbol.
2390 * The solution is to put the tag symbols that conflict into an associative
2391 * array, indexed by the address of the ordinary symbol that conflicts with it.
2392 * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
2393 * A side effect of our approach is that D code cannot access a tag symbol that is
2394 * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
2395 * has mentioned it when importing C headers. If someone wants to do it,
2396 * too bad so sad. Change the C code.
2397 * This function fixes up the symbol table when faced with adding a new symbol
2398 * `s` when there is an existing symbol `s2` with the same name.
2399 * C also allows forward and prototype declarations of tag symbols,
2400 * this function merges those.
2403 * s = symbol to add to symbol table
2404 * s2 = existing declaration
2405 * sds = symbol table
2407 * if s and s2 are successfully put in symbol table then return the merged symbol,
2408 * null if they conflict
2410 Dsymbol
handleTagSymbols(ref Scope sc
, Dsymbol s
, Dsymbol s2
, ScopeDsymbol sds
)
2413 if (log
) printf("handleTagSymbols('%s') add %p existing %p\n", s
.toChars(), s
, s2
);
2414 if (log
) printf(" add %s %s, existing %s %s\n", s
.kind(), s
.toChars(), s2
.kind(), s2
.toChars());
2415 auto sd
= s
.isScopeDsymbol(); // new declaration
2416 auto sd2
= s2
.isScopeDsymbol(); // existing declaration
2420 /* Look in tag table
2422 if (log
) printf(" look in tag table\n");
2423 if (auto p
= cast(void*)s2
in sc
._module
.tagSymTab
)
2426 sd2
= s2tag
.isScopeDsymbol();
2427 assert(sd2
); // only tags allowed in tag symbol table
2431 if (sd
&& sd2
) // `s` is a tag, `sd2` is the same tag
2433 if (log
) printf(" tag is already defined\n");
2435 if (sd
.kind() != sd2
.kind()) // being enum/struct/union must match
2436 return null; // conflict
2438 /* Not a redeclaration if one is a forward declaration.
2439 * Move members to the first declared type, which is sd2.
2444 return sd2
; // ignore the sd redeclaration
2446 else if (sd
.members
)
2448 sd2
.members
= sd
.members
; // transfer definition to sd2
2453 return sd2
; // ignore redeclaration
2455 else if (sd
) // `s` is a tag, `s2` is not
2457 if (log
) printf(" s is tag, s2 is not\n");
2458 /* add `s` as tag indexed by s2
2460 sc
._module
.tagSymTab
[cast(void*)s2
] = s
;
2463 else if (s2
is sd2
) // `s2` is a tag, `s` is not
2465 if (log
) printf(" s2 is tag, s is not\n");
2466 /* replace `s2` in symbol table with `s`,
2467 * then add `s2` as tag indexed by `s`
2469 sds
.symtab
.update(s
);
2470 sc
._module
.tagSymTab
[cast(void*)s
] = s2
;
2473 // neither s2 nor s is a tag
2474 if (log
) printf(" collision\n");
2479 /**********************************************
2480 * ImportC allows redeclarations of C variables, functions and typedefs.
2486 * Attempt to merge them.
2489 * s = symbol to add to symbol table
2490 * s2 = existing declaration
2491 * sds = symbol table
2493 * if s and s2 are successfully put in symbol table then return the merged symbol,
2494 * null if they conflict
2496 Dsymbol
handleSymbolRedeclarations(ref Scope sc
, Dsymbol s
, Dsymbol s2
, ScopeDsymbol sds
)
2499 if (log
) printf("handleSymbolRedeclarations('%s')\n", s
.toChars());
2500 if (log
) printf(" add %s %s, existing %s %s\n", s
.kind(), s
.toChars(), s2
.kind(), s2
.toChars());
2502 static Dsymbol
collision()
2504 if (log
) printf(" collision\n");
2508 auto vd
= s
.isVarDeclaration(); // new declaration
2509 auto vd2
= s2
.isVarDeclaration(); // existing declaration
2512 /* if one is `static` and the other isn't, the result is undefined
2513 * behavior, C11 6.2.2.7
2515 if ((vd
.storage_class ^ vd2
.storage_class
) & STC
.static_
)
2518 const i1
= vd
._init
&& ! vd
._init
.isVoidInitializer();
2519 const i2
= vd2
._init
&& !vd2
._init
.isVoidInitializer();
2522 return collision(); // can't both have initializers
2524 if (i1
) // vd is the definition
2526 sds
.symtab
.update(vd
); // replace vd2 with the definition
2530 /* BUG: the types should match, which needs semantic() to be run on it
2535 * long x; // collision
2536 * We incorrectly ignore these collisions
2541 auto fd
= s
.isFuncDeclaration(); // new declaration
2542 auto fd2
= s2
.isFuncDeclaration(); // existing declaration
2545 /* if one is `static` and the other isn't, the result is undefined
2546 * behavior, C11 6.2.2.7
2547 * However, match what gcc allows:
2548 * static int sun1(); int sun1() { return 0; }
2550 * static int sun2() { return 0; } int sun2();
2551 * Both produce a static function.
2553 * Both of these should fail:
2554 * int sun3(); static int sun3() { return 0; }
2556 * int sun4() { return 0; } static int sun4();
2558 // if adding `static`
2559 if ( fd
.storage_class
& STC
.static_
&&
2560 !(fd2
.storage_class
& STC
.static_
))
2565 if (fd
.fbody
&& fd2
.fbody
)
2566 return collision(); // can't both have bodies
2568 if (fd
.fbody
) // fd is the definition
2570 if (log
) printf(" replace existing with new\n");
2571 sds
.symtab
.update(fd
); // replace fd2 in symbol table with fd
2574 /* If fd2 is covering a tag symbol, then fd has to cover the same one
2576 auto ps
= cast(void*)fd2
in sc
._module
.tagSymTab
;
2578 sc
._module
.tagSymTab
[cast(void*)fd
] = *ps
;
2583 /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2584 * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
2586 fd2
.overloadInsert(fd
);
2591 auto td
= s
.isAliasDeclaration(); // new declaration
2592 auto td2
= s2
.isAliasDeclaration(); // existing declaration
2595 /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
2596 * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.