1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 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 "target.h"
28 #include "template.h"
29
30 Scope *Scope::freelist = NULL;
31
allocFieldinit(Scope * sc,size_t dim)32 void allocFieldinit(Scope *sc, size_t dim)
33 {
34 sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
35 sc->fieldinit_dim = dim;
36 }
37
freeFieldinit(Scope * sc)38 void freeFieldinit(Scope *sc)
39 {
40 if (sc->fieldinit)
41 mem.xfree(sc->fieldinit);
42 sc->fieldinit = NULL;
43 sc->fieldinit_dim = 0;
44 }
45
alloc()46 Scope *Scope::alloc()
47 {
48 if (freelist)
49 {
50 Scope *s = freelist;
51 freelist = s->enclosing;
52 //printf("freelist %p\n", s);
53 assert(s->flags & SCOPEfree);
54 s->flags &= ~SCOPEfree;
55 return s;
56 }
57
58 return new Scope();
59 }
60
Scope()61 Scope::Scope()
62 {
63 // Create root scope
64
65 //printf("Scope::Scope() %p\n", this);
66 this->_module = NULL;
67 this->scopesym = 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(Prot::public_);
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(Prot::public_);
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->enclosing = this;
155 s->slabel = NULL;
156 s->nofree = 0;
157 s->fieldinit = saveFieldInit();
158 s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
159 SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
160 SCOPEprintf | SCOPEscanf));
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
296 /****************************************
297 * Merge `b` flow analysis results into `a`.
298 * Params:
299 * a = the path to merge fi into
300 * b = the other path
301 * Returns:
302 * false means either `a` or `b` skips initialization
303 */
mergeFieldInit(unsigned & a,const unsigned b)304 static bool mergeFieldInit(unsigned &a, const unsigned b)
305 {
306 if (b == a)
307 return true;
308
309 // Have any branches returned?
310 bool aRet = (a & CSXreturn) != 0;
311 bool bRet = (b & CSXreturn) != 0;
312
313 // Have any branches halted?
314 bool aHalt = (a & CSXhalt) != 0;
315 bool bHalt = (b & CSXhalt) != 0;
316
317 if (aHalt && bHalt)
318 {
319 a = CSXhalt;
320 return true;
321 }
322
323 // The logic here is to prefer the branch that neither halts nor returns.
324 bool ok;
325 if (!bHalt && bRet)
326 {
327 // Branch b returns, no merging required.
328 ok = (b & CSXthis_ctor);
329 }
330 else if (!aHalt && aRet)
331 {
332 // Branch a returns, but b doesn't, b takes precedence.
333 ok = (a & CSXthis_ctor);
334 a = b;
335 }
336 else if (bHalt)
337 {
338 // Branch b halts, no merging required.
339 ok = (a & CSXthis_ctor);
340 }
341 else if (aHalt)
342 {
343 // Branch a halts, but b doesn't, b takes precedence
344 ok = (b & CSXthis_ctor);
345 a = b;
346 }
347 else
348 {
349 // Neither branch returns nor halts, merge flags
350 ok = !((a ^ b) & CSXthis_ctor);
351 a |= b;
352 }
353 return ok;
354 }
355
mergeFieldInit(Loc loc,unsigned * fies)356 void Scope::mergeFieldInit(Loc loc, unsigned *fies)
357 {
358 if (fieldinit && fies)
359 {
360 FuncDeclaration *f = func;
361 if (fes) f = fes->func;
362 AggregateDeclaration *ad = f->isMember2();
363 assert(ad);
364
365 for (size_t i = 0; i < ad->fields.length; i++)
366 {
367 VarDeclaration *v = ad->fields[i];
368 bool mustInit = (v->storage_class & STCnodefaultctor ||
369 v->type->needsNested());
370
371 if (!::mergeFieldInit(fieldinit[i], fies[i]) && mustInit)
372 {
373 ::error(loc, "one path skips field %s", v->toChars());
374 }
375 }
376 }
377 }
378
instantiatingModule()379 Module *Scope::instantiatingModule()
380 {
381 // TODO: in speculative context, returning 'module' is correct?
382 return minst ? minst : _module;
383 }
384
searchScopes(Scope * scope,Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)385 static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
386 {
387 for (Scope *sc = scope; sc; sc = sc->enclosing)
388 {
389 assert(sc != sc->enclosing);
390 if (!sc->scopesym)
391 continue;
392 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
393
394 if (sc->scopesym->isModule())
395 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
396
397 if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
398 {
399 if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
400 ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
401 sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
402 {
403 warning(s->loc, "array `length` hides other `length` name in outer scope");
404 }
405 if (pscopesym)
406 *pscopesym = sc->scopesym;
407 return s;
408 }
409 // Stop when we hit a module, but keep going if that is not just under the global scope
410 if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
411 break;
412 }
413 return NULL;
414 }
415
416 /************************************
417 * Perform unqualified name lookup by following the chain of scopes up
418 * until found.
419 *
420 * Params:
421 * loc = location to use for error messages
422 * ident = name to look up
423 * pscopesym = if supplied and name is found, set to scope that ident was found in
424 * flags = modify search based on flags
425 *
426 * Returns:
427 * symbol if found, null if not
428 */
search(Loc loc,Identifier * ident,Dsymbol ** pscopesym,int flags)429 Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
430 {
431 // This function is called only for unqualified lookup
432 assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
433
434 /* If ident is "start at module scope", only look at module scope
435 */
436 if (ident == Id::empty)
437 {
438 // Look for module scope
439 for (Scope *sc = this; sc; sc = sc->enclosing)
440 {
441 assert(sc != sc->enclosing);
442 if (!sc->scopesym)
443 continue;
444
445 if (Dsymbol *s = sc->scopesym->isModule())
446 {
447 if (pscopesym)
448 *pscopesym = sc->scopesym;
449 return s;
450 }
451 }
452 return NULL;
453 }
454
455 if (this->flags & SCOPEignoresymbolvisibility)
456 flags |= IgnoreSymbolVisibility;
457
458 // First look in local scopes
459 Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
460 if (!s)
461 {
462 // Second look in imported modules
463 s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
464 }
465 return s;
466 }
467
insert(Dsymbol * s)468 Dsymbol *Scope::insert(Dsymbol *s)
469 {
470 if (VarDeclaration *vd = s->isVarDeclaration())
471 {
472 if (lastVar)
473 vd->lastVar = lastVar;
474 lastVar = vd;
475 }
476 else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
477 {
478 if (VarDeclaration *wthis = ss->withstate->wthis)
479 {
480 if (lastVar)
481 wthis->lastVar = lastVar;
482 lastVar = wthis;
483 }
484 return NULL;
485 }
486 for (Scope *sc = this; sc; sc = sc->enclosing)
487 {
488 //printf("\tsc = %p\n", sc);
489 if (sc->scopesym)
490 {
491 //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
492 if (!sc->scopesym->symtab)
493 sc->scopesym->symtab = new DsymbolTable();
494 return sc->scopesym->symtabInsert(s);
495 }
496 }
497 assert(0);
498 return NULL;
499 }
500
501 /********************************************
502 * Search enclosing scopes for ClassDeclaration.
503 */
504
getClassScope()505 ClassDeclaration *Scope::getClassScope()
506 {
507 for (Scope *sc = this; sc; sc = sc->enclosing)
508 {
509 if (!sc->scopesym)
510 continue;
511
512 ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
513 if (cd)
514 return cd;
515 }
516 return NULL;
517 }
518
519 /********************************************
520 * Search enclosing scopes for ClassDeclaration.
521 */
522
getStructClassScope()523 AggregateDeclaration *Scope::getStructClassScope()
524 {
525 for (Scope *sc = this; sc; sc = sc->enclosing)
526 {
527 if (!sc->scopesym)
528 continue;
529
530 AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
531 if (ad)
532 return ad;
533 ad = sc->scopesym->isStructDeclaration();
534 if (ad)
535 return ad;
536 }
537 return NULL;
538 }
539
540 /*******************************************
541 * For TemplateDeclarations, we need to remember the Scope
542 * where it was declared. So mark the Scope as not
543 * to be free'd.
544 */
545
setNoFree()546 void Scope::setNoFree()
547 {
548 //int i = 0;
549
550 //printf("Scope::setNoFree(this = %p)\n", this);
551 for (Scope *sc = this; sc; sc = sc->enclosing)
552 {
553 //printf("\tsc = %p\n", sc);
554 sc->nofree = 1;
555
556 assert(!(flags & SCOPEfree));
557 //assert(sc != sc->enclosing);
558 //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
559 //if (++i == 10)
560 //assert(0);
561 }
562 }
563
alignment()564 structalign_t Scope::alignment()
565 {
566 if (aligndecl)
567 return aligndecl->getAlignment(this);
568 else
569 return STRUCTALIGN_DEFAULT;
570 }
571
572 /************************************************
573 * Given the failed search attempt, try to find
574 * one with a close spelling.
575 */
576
scope_search_fp(void * arg,const char * seed,int * cost)577 static void *scope_search_fp(void *arg, const char *seed, int* cost)
578 {
579 //printf("scope_search_fp('%s')\n", seed);
580
581 /* If not in the lexer's string table, it certainly isn't in the symbol table.
582 * Doing this first is a lot faster.
583 */
584 size_t len = strlen(seed);
585 if (!len)
586 return NULL;
587 Identifier *id = Identifier::lookup(seed, len);
588 if (!id)
589 return NULL;
590
591 Scope *sc = (Scope *)arg;
592 Module::clearCache();
593 Dsymbol *scopesym = NULL;
594 Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
595 if (s)
596 {
597 for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
598 if (sc->scopesym == scopesym)
599 break;
600 if (scopesym != s->parent)
601 {
602 (*cost)++; // got to the symbol through an import
603 if (s->prot().kind == Prot::private_)
604 return NULL;
605 }
606 }
607 return (void*)s;
608 }
609
search_correct(Identifier * ident)610 Dsymbol *Scope::search_correct(Identifier *ident)
611 {
612 if (global.gag)
613 return NULL; // don't do it for speculative compiles; too time consuming
614
615 Dsymbol *scopesym = NULL;
616 // search for exact name first
617 if (Dsymbol *s = search(Loc(), ident, &scopesym, IgnoreErrors))
618 return s;
619 return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
620 }
621
622 /************************************
623 * Maybe `ident` was a C or C++ name. Check for that,
624 * and suggest the D equivalent.
625 * Params:
626 * ident = unknown identifier
627 * Returns:
628 * D identifier string if found, null if not
629 */
search_correct_C(Identifier * ident)630 const char *Scope::search_correct_C(Identifier *ident)
631 {
632 TOK tok;
633 if (ident == Id::C_NULL)
634 tok = TOKnull;
635 else if (ident == Id::C_TRUE)
636 tok = TOKtrue;
637 else if (ident == Id::C_FALSE)
638 tok = TOKfalse;
639 else if (ident == Id::C_unsigned)
640 tok = TOKuns32;
641 else if (ident == Id::C_wchar_t)
642 tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
643 else
644 return NULL;
645 return Token::toChars(tok);
646 }
647