1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
9 */
10
11 #include "root/dsystem.h" // strlen()
12 #include "root/root.h"
13 #include "root/rmem.h"
14 #include "root/speller.h"
15
16 #include "mars.h"
17 #include "init.h"
18 #include "identifier.h"
19 #include "scope.h"
20 #include "attrib.h"
21 #include "dsymbol.h"
22 #include "declaration.h"
23 #include "statement.h"
24 #include "aggregate.h"
25 #include "module.h"
26 #include "id.h"
27 #include "template.h"
28
29 Scope *Scope::freelist = NULL;
30
allocFieldinit(Scope * sc,size_t dim)31 void allocFieldinit(Scope *sc, size_t dim)
32 {
33 sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
34 sc->fieldinit_dim = dim;
35 }
36
freeFieldinit(Scope * sc)37 void freeFieldinit(Scope *sc)
38 {
39 if (sc->fieldinit)
40 mem.xfree(sc->fieldinit);
41 sc->fieldinit = NULL;
42 sc->fieldinit_dim = 0;
43 }
44
alloc()45 Scope *Scope::alloc()
46 {
47 if (freelist)
48 {
49 Scope *s = freelist;
50 freelist = s->enclosing;
51 //printf("freelist %p\n", s);
52 assert(s->flags & SCOPEfree);
53 s->flags &= ~SCOPEfree;
54 return s;
55 }
56
57 return new Scope();
58 }
59
Scope()60 Scope::Scope()
61 {
62 // Create root scope
63
64 //printf("Scope::Scope() %p\n", this);
65 this->_module = NULL;
66 this->scopesym = NULL;
67 this->sds = NULL;
68 this->enclosing = NULL;
69 this->parent = NULL;
70 this->sw = NULL;
71 this->tf = NULL;
72 this->os = NULL;
73 this->tinst = NULL;
74 this->minst = NULL;
75 this->sbreak = NULL;
76 this->scontinue = NULL;
77 this->fes = NULL;
78 this->callsc = NULL;
79 this->aligndecl = NULL;
80 this->func = NULL;
81 this->slabel = NULL;
82 this->linkage = LINKd;
83 this->cppmangle = CPPMANGLEdefault;
84 this->inlining = PINLINEdefault;
85 this->protection = Prot(PROTpublic);
86 this->explicitProtection = 0;
87 this->stc = 0;
88 this->depdecl = NULL;
89 this->inunion = 0;
90 this->nofree = 0;
91 this->noctor = 0;
92 this->intypeof = 0;
93 this->lastVar = NULL;
94 this->callSuper = 0;
95 this->fieldinit = NULL;
96 this->fieldinit_dim = 0;
97 this->flags = 0;
98 this->lastdc = NULL;
99 this->anchorCounts = NULL;
100 this->prevAnchor = NULL;
101 this->userAttribDecl = NULL;
102 }
103
copy()104 Scope *Scope::copy()
105 {
106 Scope *sc = Scope::alloc();
107 *sc = *this; // memcpy
108
109 /* Bugzilla 11777: The copied scope should not inherit fieldinit.
110 */
111 sc->fieldinit = NULL;
112
113 return sc;
114 }
115
createGlobal(Module * _module)116 Scope *Scope::createGlobal(Module *_module)
117 {
118 Scope *sc = Scope::alloc();
119 *sc = Scope(); // memset
120
121 sc->aligndecl = NULL;
122 sc->linkage = LINKd;
123 sc->inlining = PINLINEdefault;
124 sc->protection = Prot(PROTpublic);
125
126 sc->_module = _module;
127
128 sc->tinst = NULL;
129 sc->minst = _module;
130
131 sc->scopesym = new ScopeDsymbol();
132 sc->scopesym->symtab = new DsymbolTable();
133
134 // Add top level package as member of this global scope
135 Dsymbol *m = _module;
136 while (m->parent)
137 m = m->parent;
138 m->addMember(NULL, sc->scopesym);
139 m->parent = NULL; // got changed by addMember()
140
141 // Create the module scope underneath the global scope
142 sc = sc->push(_module);
143 sc->parent = _module;
144 return sc;
145 }
146
push()147 Scope *Scope::push()
148 {
149 Scope *s = copy();
150
151 //printf("Scope::push(this = %p) new = %p\n", this, s);
152 assert(!(flags & SCOPEfree));
153 s->scopesym = NULL;
154 s->sds = NULL;
155 s->enclosing = this;
156 s->slabel = NULL;
157 s->nofree = 0;
158 s->fieldinit = saveFieldInit();
159 s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
160 SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
161 s->lastdc = NULL;
162
163 assert(this != s);
164 return s;
165 }
166
push(ScopeDsymbol * ss)167 Scope *Scope::push(ScopeDsymbol *ss)
168 {
169 //printf("Scope::push(%s)\n", ss->toChars());
170 Scope *s = push();
171 s->scopesym = ss;
172 return s;
173 }
174
pop()175 Scope *Scope::pop()
176 {
177 //printf("Scope::pop() %p nofree = %d\n", this, nofree);
178 Scope *enc = enclosing;
179
180 if (enclosing)
181 {
182 enclosing->callSuper |= callSuper;
183 if (fieldinit)
184 {
185 if (enclosing->fieldinit)
186 {
187 assert(fieldinit != enclosing->fieldinit);
188 size_t dim = fieldinit_dim;
189 for (size_t i = 0; i < dim; i++)
190 enclosing->fieldinit[i] |= fieldinit[i];
191 }
192 freeFieldinit(this);
193 }
194 }
195
196 if (!nofree)
197 {
198 enclosing = freelist;
199 freelist = this;
200 flags |= SCOPEfree;
201 }
202
203 return enc;
204 }
205
startCTFE()206 Scope *Scope::startCTFE()
207 {
208 Scope *sc = this->push();
209 sc->flags = this->flags | SCOPEctfe;
210 return sc;
211 }
212
endCTFE()213 Scope *Scope::endCTFE()
214 {
215 assert(flags & SCOPEctfe);
216 return pop();
217 }
218
mergeCallSuper(Loc loc,unsigned cs)219 void Scope::mergeCallSuper(Loc loc, unsigned cs)
220 {
221 // This does a primitive flow analysis to support the restrictions
222 // regarding when and how constructors can appear.
223 // It merges the results of two paths.
224 // The two paths are callSuper and cs; the result is merged into callSuper.
225
226 if (cs != callSuper)
227 {
228 // Have ALL branches called a constructor?
229 int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
230 int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
231
232 // Have ANY branches called a constructor?
233 bool aAny = (cs & CSXany_ctor) != 0;
234 bool bAny = (callSuper & CSXany_ctor) != 0;
235
236 // Have any branches returned?
237 bool aRet = (cs & CSXreturn) != 0;
238 bool bRet = (callSuper & CSXreturn) != 0;
239
240 // Have any branches halted?
241 bool aHalt = (cs & CSXhalt) != 0;
242 bool bHalt = (callSuper & CSXhalt) != 0;
243
244 bool ok = true;
245
246 if (aHalt && bHalt)
247 {
248 callSuper = CSXhalt;
249 }
250 else if ((!aHalt && aRet && !aAny && bAny) ||
251 (!bHalt && bRet && !bAny && aAny))
252 {
253 // If one has returned without a constructor call, there must be never
254 // have been ctor calls in the other.
255 ok = false;
256 }
257 else if (aHalt || (aRet && aAll))
258 {
259 // If one branch has called a ctor and then exited, anything the
260 // other branch has done is OK (except returning without a
261 // ctor call, but we already checked that).
262 callSuper |= cs & (CSXany_ctor | CSXlabel);
263 }
264 else if (bHalt || (bRet && bAll))
265 {
266 callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
267 }
268 else
269 {
270 // Both branches must have called ctors, or both not.
271 ok = (aAll == bAll);
272 // If one returned without a ctor, we must remember that
273 // (Don't bother if we've already found an error)
274 if (ok && aRet && !aAny)
275 callSuper |= CSXreturn;
276 callSuper |= cs & (CSXany_ctor | CSXlabel);
277 }
278 if (!ok)
279 error(loc, "one path skips constructor");
280 }
281 }
282
saveFieldInit()283 unsigned *Scope::saveFieldInit()
284 {
285 unsigned *fi = NULL;
286 if (fieldinit) // copy
287 {
288 size_t dim = fieldinit_dim;
289 fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
290 for (size_t i = 0; i < dim; i++)
291 fi[i] = fieldinit[i];
292 }
293 return fi;
294 }
295
mergeFieldInit(unsigned & fieldInit,unsigned fi,bool mustInit)296 static bool mergeFieldInit(unsigned &fieldInit, unsigned fi, bool mustInit)
297 {
298 if (fi != fieldInit)
299 {
300 // Have any branches returned?
301 bool aRet = (fi & CSXreturn) != 0;
302 bool bRet = (fieldInit & CSXreturn) != 0;
303
304 // Have any branches halted?
305 bool aHalt = (fi & CSXhalt) != 0;
306 bool bHalt = (fieldInit & CSXhalt) != 0;
307
308 bool ok;
309
310 if (aHalt && bHalt)
311 {
312 ok = true;
313 fieldInit = CSXhalt;
314 }
315 else if (!aHalt && aRet)
316 {
317 ok = !mustInit || (fi & CSXthis_ctor);
318 fieldInit = fieldInit;
319 }
320 else if (!bHalt && bRet)
321 {
322 ok = !mustInit || (fieldInit & CSXthis_ctor);
323 fieldInit = fi;
324 }
325 else if (aHalt)
326 {
327 ok = !mustInit || (fieldInit & CSXthis_ctor);
328 fieldInit = fieldInit;
329 }
330 else if (bHalt)
331 {
332 ok = !mustInit || (fi & CSXthis_ctor);
333 fieldInit = fi;
334 }
335 else
336 {
337 ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor);
338 fieldInit |= fi;
339 }
340
341 return ok;
342 }
343 return true;
344 }
345
mergeFieldInit(Loc loc,unsigned * fies)346 void Scope::mergeFieldInit(Loc loc, unsigned *fies)
347 {
348 if (fieldinit && fies)
349 {
350 FuncDeclaration *f = func;
351 if (fes) f = fes->func;
352 AggregateDeclaration *ad = f->isMember2();
353 assert(ad);
354
355 for (size_t i = 0; i < ad->fields.dim; i++)
356 {
357 VarDeclaration *v = ad->fields[i];
358 bool mustInit = (v->storage_class & STCnodefaultctor ||
359 v->type->needsNested());
360
361 if (!::mergeFieldInit(fieldinit[i], fies[i], mustInit))
362 {
363 ::error(loc, "one path skips field %s", ad->fields[i]->toChars());
364 }
365 }
366 }
367 }
368
instantiatingModule()369 Module *Scope::instantiatingModule()
370 {
371 // TODO: in speculative context, returning 'module' is correct?
372 return minst ? minst : _module;
373 }
374
searchScopes(Scope * scope,Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)375 static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
376 {
377 for (Scope *sc = scope; sc; sc = sc->enclosing)
378 {
379 assert(sc != sc->enclosing);
380 if (!sc->scopesym)
381 continue;
382 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
383
384 if (sc->scopesym->isModule())
385 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
386
387 if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
388 {
389 if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
390 ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
391 sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
392 {
393 warning(s->loc, "array 'length' hides other 'length' name in outer scope");
394 }
395 if (pscopesym)
396 *pscopesym = sc->scopesym;
397 return s;
398 }
399 // Stop when we hit a module, but keep going if that is not just under the global scope
400 if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
401 break;
402 }
403 return NULL;
404 }
405
406 /************************************
407 * Perform unqualified name lookup by following the chain of scopes up
408 * until found.
409 *
410 * Params:
411 * loc = location to use for error messages
412 * ident = name to look up
413 * pscopesym = if supplied and name is found, set to scope that ident was found in
414 * flags = modify search based on flags
415 *
416 * Returns:
417 * symbol if found, null if not
418 */
search(Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)419 Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
420 {
421 // This function is called only for unqualified lookup
422 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
423
424 /* If ident is "start at module scope", only look at module scope
425 */
426 if (ident == Id::empty)
427 {
428 // Look for module scope
429 for (Scope *sc = this; sc; sc = sc->enclosing)
430 {
431 assert(sc != sc->enclosing);
432 if (!sc->scopesym)
433 continue;
434
435 if (Dsymbol *s = sc->scopesym->isModule())
436 {
437 if (pscopesym)
438 *pscopesym = sc->scopesym;
439 return s;
440 }
441 }
442 return NULL;
443 }
444
445 if (this->flags & SCOPEignoresymbolvisibility)
446 flags |= IgnoreSymbolVisibility;
447
448 Dsymbol *sold = NULL;
449 if (global.params.bug10378 || global.params.check10378)
450 {
451 sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility);
452 if (!global.params.check10378)
453 return sold;
454
455 if (ident == Id::dollar) // Bugzilla 15825
456 return sold;
457
458 // Search both ways
459 }
460
461 // First look in local scopes
462 Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
463 if (!s)
464 {
465 // Second look in imported modules
466 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
467 /** Still find private symbols, so that symbols that weren't access
468 * checked by the compiler remain usable. Once the deprecation is over,
469 * this should be moved to search_correct instead.
470 */
471 if (!s && !(flags & IgnoreSymbolVisibility))
472 {
473 s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
474 if (!s)
475 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility);
476
477 if (s && !(flags & IgnoreErrors))
478 ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars());
479 }
480 }
481
482 if (global.params.check10378)
483 {
484 Dsymbol *snew = s;
485 if (sold != snew)
486 deprecation10378(loc, sold, snew);
487 if (global.params.bug10378)
488 s = sold;
489 }
490 return s;
491 }
492
insert(Dsymbol * s)493 Dsymbol *Scope::insert(Dsymbol *s)
494 {
495 if (VarDeclaration *vd = s->isVarDeclaration())
496 {
497 if (lastVar)
498 vd->lastVar = lastVar;
499 lastVar = vd;
500 }
501 else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
502 {
503 if (VarDeclaration *vd = ss->withstate->wthis)
504 {
505 if (lastVar)
506 vd->lastVar = lastVar;
507 lastVar = vd;
508 }
509 return NULL;
510 }
511 for (Scope *sc = this; sc; sc = sc->enclosing)
512 {
513 //printf("\tsc = %p\n", sc);
514 if (sc->scopesym)
515 {
516 //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
517 if (!sc->scopesym->symtab)
518 sc->scopesym->symtab = new DsymbolTable();
519 return sc->scopesym->symtabInsert(s);
520 }
521 }
522 assert(0);
523 return NULL;
524 }
525
526 /********************************************
527 * Search enclosing scopes for ClassDeclaration.
528 */
529
getClassScope()530 ClassDeclaration *Scope::getClassScope()
531 {
532 for (Scope *sc = this; sc; sc = sc->enclosing)
533 {
534 if (!sc->scopesym)
535 continue;
536
537 ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
538 if (cd)
539 return cd;
540 }
541 return NULL;
542 }
543
544 /********************************************
545 * Search enclosing scopes for ClassDeclaration.
546 */
547
getStructClassScope()548 AggregateDeclaration *Scope::getStructClassScope()
549 {
550 for (Scope *sc = this; sc; sc = sc->enclosing)
551 {
552 if (!sc->scopesym)
553 continue;
554
555 AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
556 if (ad)
557 return ad;
558 ad = sc->scopesym->isStructDeclaration();
559 if (ad)
560 return ad;
561 }
562 return NULL;
563 }
564
565 /*******************************************
566 * For TemplateDeclarations, we need to remember the Scope
567 * where it was declared. So mark the Scope as not
568 * to be free'd.
569 */
570
setNoFree()571 void Scope::setNoFree()
572 {
573 //int i = 0;
574
575 //printf("Scope::setNoFree(this = %p)\n", this);
576 for (Scope *sc = this; sc; sc = sc->enclosing)
577 {
578 //printf("\tsc = %p\n", sc);
579 sc->nofree = 1;
580
581 assert(!(flags & SCOPEfree));
582 //assert(sc != sc->enclosing);
583 //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
584 //if (++i == 10)
585 //assert(0);
586 }
587 }
588
alignment()589 structalign_t Scope::alignment()
590 {
591 if (aligndecl)
592 return aligndecl->getAlignment(this);
593 else
594 return STRUCTALIGN_DEFAULT;
595 }
596
597 /************************************************
598 * Given the failed search attempt, try to find
599 * one with a close spelling.
600 */
601
scope_search_fp(void * arg,const char * seed,int * cost)602 void *scope_search_fp(void *arg, const char *seed, int* cost)
603 {
604 //printf("scope_search_fp('%s')\n", seed);
605
606 /* If not in the lexer's string table, it certainly isn't in the symbol table.
607 * Doing this first is a lot faster.
608 */
609 size_t len = strlen(seed);
610 if (!len)
611 return NULL;
612 Identifier *id = Identifier::lookup(seed, len);
613 if (!id)
614 return NULL;
615
616 Scope *sc = (Scope *)arg;
617 Module::clearCache();
618 Dsymbol *scopesym = NULL;
619 Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
620 if (s)
621 {
622 for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
623 if (sc->scopesym == scopesym)
624 break;
625 if (scopesym != s->parent)
626 {
627 (*cost)++; // got to the symbol through an import
628 if (s->prot().kind == PROTprivate)
629 return NULL;
630 }
631 }
632 return (void*)s;
633 }
634
deprecation10378(Loc loc,Dsymbol * sold,Dsymbol * snew)635 void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew)
636 {
637 // Bugzilla 15857
638 //
639 // The overloadset found via the new lookup rules is either
640 // equal or a subset of the overloadset found via the old
641 // lookup rules, so it suffices to compare the dimension to
642 // check for equality.
643 OverloadSet *osold = NULL;
644 OverloadSet *osnew = NULL;
645 if (sold && (osold = sold->isOverloadSet()) != NULL &&
646 snew && (osnew = snew->isOverloadSet()) != NULL &&
647 osold->a.dim == osnew->a.dim)
648 return;
649
650 OutBuffer buf;
651 buf.writestring("local import search method found ");
652 if (osold)
653 buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim);
654 else if (sold)
655 buf.printf("%s %s", sold->kind(), sold->toPrettyChars());
656 else
657 buf.writestring("nothing");
658 buf.writestring(" instead of ");
659 if (osnew)
660 buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim);
661 else if (snew)
662 buf.printf("%s %s", snew->kind(), snew->toPrettyChars());
663 else
664 buf.writestring("nothing");
665
666 deprecation(loc, "%s", buf.peekString());
667 }
668
search_correct(Identifier * ident)669 Dsymbol *Scope::search_correct(Identifier *ident)
670 {
671 if (global.gag)
672 return NULL; // don't do it for speculative compiles; too time consuming
673
674 return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
675 }
676
677 /************************************
678 * Maybe `ident` was a C or C++ name. Check for that,
679 * and suggest the D equivalent.
680 * Params:
681 * ident = unknown identifier
682 * Returns:
683 * D identifier string if found, null if not
684 */
search_correct_C(Identifier * ident)685 const char *Scope::search_correct_C(Identifier *ident)
686 {
687 TOK tok;
688 if (ident == Id::C_NULL)
689 tok = TOKnull;
690 else if (ident == Id::C_TRUE)
691 tok = TOKtrue;
692 else if (ident == Id::C_FALSE)
693 tok = TOKfalse;
694 else if (ident == Id::C_unsigned)
695 tok = TOKuns32;
696 else if (ident == Id::C_wchar_t)
697 tok = global.params.isWindows ? TOKwchar : TOKdchar;
698 else
699 return NULL;
700 return Token::toChars(tok);
701 }
702