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