]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/access.c
37e9c8681d30a0fca3623f34d73215b9a85fcb9d
[thirdparty/gcc.git] / gcc / d / dmd / access.c
1 /* Compiler implementation of the D programming language
2 * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
3 * written by Walter Bright
4 * http://www.digitalmars.com
5 * Distributed under the Boost Software License, Version 1.0.
6 * http://www.boost.org/LICENSE_1_0.txt
7 * https://github.com/D-Programming-Language/dmd/blob/master/src/access.c
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <assert.h>
13
14 #include "root/root.h"
15 #include "root/rmem.h"
16
17 #include "errors.h"
18 #include "enum.h"
19 #include "aggregate.h"
20 #include "init.h"
21 #include "attrib.h"
22 #include "scope.h"
23 #include "id.h"
24 #include "mtype.h"
25 #include "declaration.h"
26 #include "aggregate.h"
27 #include "expression.h"
28 #include "module.h"
29 #include "template.h"
30
31 /* Code to do access checks
32 */
33
34 bool hasPackageAccess(Scope *sc, Dsymbol *s);
35 bool hasPackageAccess(Module *mod, Dsymbol *s);
36 bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
37 bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);
38 static Dsymbol *mostVisibleOverload(Dsymbol *s);
39
40 /****************************************
41 * Return Prot access for Dsymbol smember in this declaration.
42 */
43 Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
44 {
45 Prot access_ret = Prot(PROTnone);
46
47 assert(ad->isStructDeclaration() || ad->isClassDeclaration());
48 if (smember->toParent() == ad)
49 {
50 access_ret = smember->prot();
51 }
52 else if (smember->isDeclaration()->isStatic())
53 {
54 access_ret = smember->prot();
55 }
56 if (ClassDeclaration *cd = ad->isClassDeclaration())
57 {
58 for (size_t i = 0; i < cd->baseclasses->dim; i++)
59 {
60 BaseClass *b = (*cd->baseclasses)[i];
61
62 Prot access = getAccess(b->sym, smember);
63 switch (access.kind)
64 {
65 case PROTnone:
66 break;
67
68 case PROTprivate:
69 access_ret = Prot(PROTnone); // private members of base class not accessible
70 break;
71
72 case PROTpackage:
73 case PROTprotected:
74 case PROTpublic:
75 case PROTexport:
76 // If access is to be tightened
77 if (PROTpublic < access.kind)
78 access = Prot(PROTpublic);
79
80 // Pick path with loosest access
81 if (access_ret.isMoreRestrictiveThan(access))
82 access_ret = access;
83 break;
84
85 default:
86 assert(0);
87 }
88 }
89 }
90
91 return access_ret;
92 }
93
94 /********************************************************
95 * Helper function for checkAccess()
96 * Returns:
97 * false is not accessible
98 * true is accessible
99 */
100 static bool isAccessible(
101 Dsymbol *smember,
102 Dsymbol *sfunc,
103 AggregateDeclaration *dthis,
104 AggregateDeclaration *cdscope)
105 {
106 assert(dthis);
107
108 if (hasPrivateAccess(dthis, sfunc) ||
109 isFriendOf(dthis, cdscope))
110 {
111 if (smember->toParent() == dthis)
112 return true;
113
114 if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
115 {
116 for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
117 {
118 BaseClass *b = (*cdthis->baseclasses)[i];
119 Prot access = getAccess(b->sym, smember);
120 if (access.kind >= PROTprotected ||
121 isAccessible(smember, sfunc, b->sym, cdscope))
122 {
123 return true;
124 }
125 }
126 }
127 }
128 else
129 {
130 if (smember->toParent() != dthis)
131 {
132 if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
133 {
134 for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
135 {
136 BaseClass *b = (*cdthis->baseclasses)[i];
137 if (isAccessible(smember, sfunc, b->sym, cdscope))
138 return true;
139 }
140 }
141 }
142 }
143 return false;
144 }
145
146 /*******************************
147 * Do access check for member of this class, this class being the
148 * type of the 'this' pointer used to access smember.
149 * Returns true if the member is not accessible.
150 */
151 bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
152 {
153 FuncDeclaration *f = sc->func;
154 AggregateDeclaration *cdscope = sc->getStructClassScope();
155
156 Dsymbol *smemberparent = smember->toParent();
157 if (!smemberparent || !smemberparent->isAggregateDeclaration())
158 {
159 return false; // then it is accessible
160 }
161
162 // BUG: should enable this check
163 //assert(smember->parent->isBaseOf(this, NULL));
164
165 bool result;
166 Prot access;
167 if (smemberparent == ad)
168 {
169 access = smember->prot();
170 result = access.kind >= PROTpublic ||
171 hasPrivateAccess(ad, f) ||
172 isFriendOf(ad, cdscope) ||
173 (access.kind == PROTpackage && hasPackageAccess(sc, smember)) ||
174 ad->getAccessModule() == sc->_module;
175 }
176 else if ((access = getAccess(ad, smember)).kind >= PROTpublic)
177 {
178 result = true;
179 }
180 else if (access.kind == PROTpackage && hasPackageAccess(sc, ad))
181 {
182 result = true;
183 }
184 else
185 {
186 result = isAccessible(smember, f, ad, cdscope);
187 }
188 if (!result)
189 {
190 ad->error(loc, "member %s is not accessible", smember->toChars());
191 //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
192 // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
193 return true;
194 }
195 return false;
196 }
197
198 /****************************************
199 * Determine if this is the same or friend of cd.
200 */
201 bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
202 {
203 if (ad == cd)
204 return true;
205
206 // Friends if both are in the same module
207 //if (toParent() == cd->toParent())
208 if (cd && ad->getAccessModule() == cd->getAccessModule())
209 {
210 return true;
211 }
212
213 return false;
214 }
215
216 /****************************************
217 * Determine if scope sc has package level access to s.
218 */
219 bool hasPackageAccess(Scope *sc, Dsymbol *s)
220 {
221 return hasPackageAccess(sc->_module, s);
222 }
223
224 bool hasPackageAccess(Module *mod, Dsymbol *s)
225 {
226 Package *pkg = NULL;
227
228 if (s->prot().pkg)
229 pkg = s->prot().pkg;
230 else
231 {
232 // no explicit package for protection, inferring most qualified one
233 for (; s; s = s->parent)
234 {
235 if (Module *m = s->isModule())
236 {
237 DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
238 assert(dst);
239 Dsymbol *s2 = dst->lookup(m->ident);
240 assert(s2);
241 Package *p = s2->isPackage();
242 if (p && p->isPackageMod())
243 {
244 pkg = p;
245 break;
246 }
247 }
248 else if ((pkg = s->isPackage()) != NULL)
249 break;
250 }
251 }
252
253 if (pkg)
254 {
255 if (pkg == mod->parent)
256 {
257 return true;
258 }
259 if (pkg->isPackageMod() == mod)
260 {
261 return true;
262 }
263 Dsymbol* ancestor = mod->parent;
264 for (; ancestor; ancestor = ancestor->parent)
265 {
266 if (ancestor == pkg)
267 {
268 return true;
269 }
270 }
271 }
272
273 return false;
274 }
275
276 /****************************************
277 * Determine if scope sc has protected level access to cd.
278 */
279 bool hasProtectedAccess(Scope *sc, Dsymbol *s)
280 {
281 if (ClassDeclaration *cd = s->isClassMember()) // also includes interfaces
282 {
283 for (Scope *scx = sc; scx; scx = scx->enclosing)
284 {
285 if (!scx->scopesym)
286 continue;
287 ClassDeclaration *cd2 = scx->scopesym->isClassDeclaration();
288 if (cd2 && cd->isBaseOf(cd2, NULL))
289 return true;
290 }
291 }
292 return sc->_module == s->getAccessModule();
293 }
294
295 /**********************************
296 * Determine if smember has access to private members of this declaration.
297 */
298 bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember)
299 {
300 if (smember)
301 {
302 AggregateDeclaration *cd = NULL;
303 Dsymbol *smemberparent = smember->toParent();
304 if (smemberparent)
305 cd = smemberparent->isAggregateDeclaration();
306
307 if (ad == cd) // smember is a member of this class
308 {
309 return true; // so we get private access
310 }
311
312 // If both are members of the same module, grant access
313 while (1)
314 {
315 Dsymbol *sp = smember->toParent();
316 if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
317 smember = sp;
318 else
319 break;
320 }
321 if (!cd && ad->toParent() == smember->toParent())
322 {
323 return true;
324 }
325 if (!cd && ad->getAccessModule() == smember->getAccessModule())
326 {
327 return true;
328 }
329 }
330 return false;
331 }
332
333 /****************************************
334 * Check access to d for expression e.d
335 * Returns true if the declaration is not accessible.
336 */
337 bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d)
338 {
339 if (sc->flags & SCOPEnoaccesscheck)
340 return false;
341
342 if (d->isUnitTestDeclaration())
343 {
344 // Unittests are always accessible.
345 return false;
346 }
347 if (!e)
348 {
349 if ((d->prot().kind == PROTprivate && d->getAccessModule() != sc->_module) ||
350 (d->prot().kind == PROTpackage && !hasPackageAccess(sc, d)))
351 {
352 error(loc, "%s %s is not accessible from module %s",
353 d->kind(), d->toPrettyChars(), sc->_module->toChars());
354 return true;
355 }
356 }
357 else if (e->type->ty == Tclass)
358 {
359 // Do access check
360 ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
361 if (e->op == TOKsuper)
362 {
363 ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
364 if (cd2)
365 cd = cd2;
366 }
367 return checkAccess(cd, loc, sc, d);
368 }
369 else if (e->type->ty == Tstruct)
370 {
371 // Do access check
372 StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
373 return checkAccess(cd, loc, sc, d);
374 }
375 return false;
376 }
377
378 /****************************************
379 * Check access to package/module `p` from scope `sc`.
380 *
381 * Params:
382 * loc = source location for issued error message
383 * sc = scope from which to access to a fully qualified package name
384 * p = the package/module to check access for
385 * Returns: true if the package is not accessible.
386 *
387 * Because a global symbol table tree is used for imported packages/modules,
388 * access to them needs to be checked based on the imports in the scope chain
389 * (see Bugzilla 313).
390 *
391 */
392 bool checkAccess(Loc loc, Scope *sc, Package *p)
393 {
394 if (sc->_module == p)
395 return false;
396 for (; sc; sc = sc->enclosing)
397 {
398 if (sc->scopesym && sc->scopesym->isPackageAccessible(p, Prot(PROTprivate)))
399 return false;
400 }
401 const char *name = p->toPrettyChars();
402 if (p->isPkgMod == PKGmodule || p->isModule())
403 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", p->kind(), name, name);
404 else
405 deprecation(loc, "%s %s is not accessible here", p->kind(), name);
406 return true;
407 }
408
409 /**
410 * Check whether symbols `s` is visible in `mod`.
411 *
412 * Params:
413 * mod = lookup origin
414 * s = symbol to check for visibility
415 * Returns: true if s is visible in mod
416 */
417 bool symbolIsVisible(Module *mod, Dsymbol *s)
418 {
419 // should sort overloads by ascending protection instead of iterating here
420 s = mostVisibleOverload(s);
421
422 switch (s->prot().kind)
423 {
424 case PROTundefined:
425 return true;
426 case PROTnone:
427 return false; // no access
428 case PROTprivate:
429 return s->getAccessModule() == mod;
430 case PROTpackage:
431 return s->getAccessModule() == mod || hasPackageAccess(mod, s);
432 case PROTprotected:
433 return s->getAccessModule() == mod;
434 case PROTpublic:
435 case PROTexport:
436 return true;
437 default:
438 assert(0);
439 }
440 }
441
442 /**
443 * Same as above, but determines the lookup module from symbols `origin`.
444 */
445 bool symbolIsVisible(Dsymbol *origin, Dsymbol *s)
446 {
447 return symbolIsVisible(origin->getAccessModule(), s);
448 }
449
450 /**
451 * Same as above but also checks for protected symbols visible from scope `sc`.
452 * Used for qualified name lookup.
453 *
454 * Params:
455 * sc = lookup scope
456 * s = symbol to check for visibility
457 * Returns: true if s is visible by origin
458 */
459 bool symbolIsVisible(Scope *sc, Dsymbol *s)
460 {
461 s = mostVisibleOverload(s);
462
463 switch (s->prot().kind)
464 {
465 case PROTundefined:
466 return true;
467 case PROTnone:
468 return false; // no access
469 case PROTprivate:
470 return sc->_module == s->getAccessModule();
471 case PROTpackage:
472 return sc->_module == s->getAccessModule() || hasPackageAccess(sc->_module, s);
473 case PROTprotected:
474 return hasProtectedAccess(sc, s);
475 case PROTpublic:
476 case PROTexport:
477 return true;
478 default:
479 assert(0);
480 }
481 }
482
483 /**
484 * Use the most visible overload to check visibility. Later perform an access
485 * check on the resolved overload. This function is similar to overloadApply,
486 * but doesn't recurse nor resolve aliases because protection/visibility is an
487 * attribute of the alias not the aliasee.
488 */
489 static Dsymbol *mostVisibleOverload(Dsymbol *s)
490 {
491 if (!s->isOverloadable())
492 return s;
493
494 Dsymbol *next = NULL;
495 Dsymbol *fstart = s;
496 Dsymbol *mostVisible = s;
497 for (; s; s = next)
498 {
499 // void func() {}
500 // private void func(int) {}
501 if (FuncDeclaration *fd = s->isFuncDeclaration())
502 next = fd->overnext;
503 // template temp(T) {}
504 // private template temp(T:int) {}
505 else if (TemplateDeclaration *td = s->isTemplateDeclaration())
506 next = td->overnext;
507 // alias common = mod1.func1;
508 // alias common = mod2.func2;
509 else if (FuncAliasDeclaration *fa = s->isFuncAliasDeclaration())
510 next = fa->overnext;
511 // alias common = mod1.templ1;
512 // alias common = mod2.templ2;
513 else if (OverDeclaration *od = s->isOverDeclaration())
514 next = od->overnext;
515 // alias name = sym;
516 // private void name(int) {}
517 else if (AliasDeclaration *ad = s->isAliasDeclaration())
518 {
519 if (!ad->isOverloadable())
520 {
521 //printf("Non overloadable Aliasee in overload list\n");
522 assert(0);
523 }
524 // Yet unresolved aliases store overloads in overnext.
525 if (ad->semanticRun < PASSsemanticdone)
526 next = ad->overnext;
527 else
528 {
529 /* This is a bit messy due to the complicated implementation of
530 * alias. Aliases aren't overloadable themselves, but if their
531 * Aliasee is overloadable they can be converted to an overloadable
532 * alias.
533 *
534 * This is done by replacing the Aliasee w/ FuncAliasDeclaration
535 * (for functions) or OverDeclaration (for templates) which are
536 * simply overloadable aliases w/ weird names.
537 *
538 * Usually aliases should not be resolved for visibility checking
539 * b/c public aliases to private symbols are public. But for the
540 * overloadable alias situation, the Alias (_ad_) has been moved
541 * into it's own Aliasee, leaving a shell that we peel away here.
542 */
543 Dsymbol *aliasee = ad->toAlias();
544 if (aliasee->isFuncAliasDeclaration() || aliasee->isOverDeclaration())
545 next = aliasee;
546 else
547 {
548 /* A simple alias can be at the end of a function or template overload chain.
549 * It can't have further overloads b/c it would have been
550 * converted to an overloadable alias.
551 */
552 if (ad->overnext)
553 {
554 //printf("Unresolved overload of alias\n");
555 assert(0);
556 }
557 break;
558 }
559 }
560
561 // handled by overloadApply for unknown reason
562 assert(next != ad); // should not alias itself
563 assert(next != fstart); // should not alias the overload list itself
564 }
565 else
566 break;
567
568 if (next && mostVisible->prot().isMoreRestrictiveThan(next->prot()))
569 mostVisible = next;
570 }
571 return mostVisible;
572 }