]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/access.c
37e9c8681d30a0fca3623f34d73215b9a85fcb9d
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
14 #include "root/root.h"
15 #include "root/rmem.h"
19 #include "aggregate.h"
25 #include "declaration.h"
26 #include "aggregate.h"
27 #include "expression.h"
31 /* Code to do access checks
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
);
40 /****************************************
41 * Return Prot access for Dsymbol smember in this declaration.
43 Prot
getAccess(AggregateDeclaration
*ad
, Dsymbol
*smember
)
45 Prot access_ret
= Prot(PROTnone
);
47 assert(ad
->isStructDeclaration() || ad
->isClassDeclaration());
48 if (smember
->toParent() == ad
)
50 access_ret
= smember
->prot();
52 else if (smember
->isDeclaration()->isStatic())
54 access_ret
= smember
->prot();
56 if (ClassDeclaration
*cd
= ad
->isClassDeclaration())
58 for (size_t i
= 0; i
< cd
->baseclasses
->dim
; i
++)
60 BaseClass
*b
= (*cd
->baseclasses
)[i
];
62 Prot access
= getAccess(b
->sym
, smember
);
69 access_ret
= Prot(PROTnone
); // private members of base class not accessible
76 // If access is to be tightened
77 if (PROTpublic
< access
.kind
)
78 access
= Prot(PROTpublic
);
80 // Pick path with loosest access
81 if (access_ret
.isMoreRestrictiveThan(access
))
94 /********************************************************
95 * Helper function for checkAccess()
97 * false is not accessible
100 static bool isAccessible(
103 AggregateDeclaration
*dthis
,
104 AggregateDeclaration
*cdscope
)
108 if (hasPrivateAccess(dthis
, sfunc
) ||
109 isFriendOf(dthis
, cdscope
))
111 if (smember
->toParent() == dthis
)
114 if (ClassDeclaration
*cdthis
= dthis
->isClassDeclaration())
116 for (size_t i
= 0; i
< cdthis
->baseclasses
->dim
; i
++)
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
))
130 if (smember
->toParent() != dthis
)
132 if (ClassDeclaration
*cdthis
= dthis
->isClassDeclaration())
134 for (size_t i
= 0; i
< cdthis
->baseclasses
->dim
; i
++)
136 BaseClass
*b
= (*cdthis
->baseclasses
)[i
];
137 if (isAccessible(smember
, sfunc
, b
->sym
, cdscope
))
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.
151 bool checkAccess(AggregateDeclaration
*ad
, Loc loc
, Scope
*sc
, Dsymbol
*smember
)
153 FuncDeclaration
*f
= sc
->func
;
154 AggregateDeclaration
*cdscope
= sc
->getStructClassScope();
156 Dsymbol
*smemberparent
= smember
->toParent();
157 if (!smemberparent
|| !smemberparent
->isAggregateDeclaration())
159 return false; // then it is accessible
162 // BUG: should enable this check
163 //assert(smember->parent->isBaseOf(this, NULL));
167 if (smemberparent
== ad
)
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
;
176 else if ((access
= getAccess(ad
, smember
)).kind
>= PROTpublic
)
180 else if (access
.kind
== PROTpackage
&& hasPackageAccess(sc
, ad
))
186 result
= isAccessible(smember
, f
, ad
, cdscope
);
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);
198 /****************************************
199 * Determine if this is the same or friend of cd.
201 bool isFriendOf(AggregateDeclaration
*ad
, AggregateDeclaration
*cd
)
206 // Friends if both are in the same module
207 //if (toParent() == cd->toParent())
208 if (cd
&& ad
->getAccessModule() == cd
->getAccessModule())
216 /****************************************
217 * Determine if scope sc has package level access to s.
219 bool hasPackageAccess(Scope
*sc
, Dsymbol
*s
)
221 return hasPackageAccess(sc
->_module
, s
);
224 bool hasPackageAccess(Module
*mod
, Dsymbol
*s
)
232 // no explicit package for protection, inferring most qualified one
233 for (; s
; s
= s
->parent
)
235 if (Module
*m
= s
->isModule())
237 DsymbolTable
*dst
= Package::resolve(m
->md
? m
->md
->packages
: NULL
, NULL
, NULL
);
239 Dsymbol
*s2
= dst
->lookup(m
->ident
);
241 Package
*p
= s2
->isPackage();
242 if (p
&& p
->isPackageMod())
248 else if ((pkg
= s
->isPackage()) != NULL
)
255 if (pkg
== mod
->parent
)
259 if (pkg
->isPackageMod() == mod
)
263 Dsymbol
* ancestor
= mod
->parent
;
264 for (; ancestor
; ancestor
= ancestor
->parent
)
276 /****************************************
277 * Determine if scope sc has protected level access to cd.
279 bool hasProtectedAccess(Scope
*sc
, Dsymbol
*s
)
281 if (ClassDeclaration
*cd
= s
->isClassMember()) // also includes interfaces
283 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
287 ClassDeclaration
*cd2
= scx
->scopesym
->isClassDeclaration();
288 if (cd2
&& cd
->isBaseOf(cd2
, NULL
))
292 return sc
->_module
== s
->getAccessModule();
295 /**********************************
296 * Determine if smember has access to private members of this declaration.
298 bool hasPrivateAccess(AggregateDeclaration
*ad
, Dsymbol
*smember
)
302 AggregateDeclaration
*cd
= NULL
;
303 Dsymbol
*smemberparent
= smember
->toParent();
305 cd
= smemberparent
->isAggregateDeclaration();
307 if (ad
== cd
) // smember is a member of this class
309 return true; // so we get private access
312 // If both are members of the same module, grant access
315 Dsymbol
*sp
= smember
->toParent();
316 if (sp
->isFuncDeclaration() && smember
->isFuncDeclaration())
321 if (!cd
&& ad
->toParent() == smember
->toParent())
325 if (!cd
&& ad
->getAccessModule() == smember
->getAccessModule())
333 /****************************************
334 * Check access to d for expression e.d
335 * Returns true if the declaration is not accessible.
337 bool checkAccess(Loc loc
, Scope
*sc
, Expression
*e
, Declaration
*d
)
339 if (sc
->flags
& SCOPEnoaccesscheck
)
342 if (d
->isUnitTestDeclaration())
344 // Unittests are always accessible.
349 if ((d
->prot().kind
== PROTprivate
&& d
->getAccessModule() != sc
->_module
) ||
350 (d
->prot().kind
== PROTpackage
&& !hasPackageAccess(sc
, d
)))
352 error(loc
, "%s %s is not accessible from module %s",
353 d
->kind(), d
->toPrettyChars(), sc
->_module
->toChars());
357 else if (e
->type
->ty
== Tclass
)
360 ClassDeclaration
*cd
= (ClassDeclaration
*)(((TypeClass
*)e
->type
)->sym
);
361 if (e
->op
== TOKsuper
)
363 ClassDeclaration
*cd2
= sc
->func
->toParent()->isClassDeclaration();
367 return checkAccess(cd
, loc
, sc
, d
);
369 else if (e
->type
->ty
== Tstruct
)
372 StructDeclaration
*cd
= (StructDeclaration
*)(((TypeStruct
*)e
->type
)->sym
);
373 return checkAccess(cd
, loc
, sc
, d
);
378 /****************************************
379 * Check access to package/module `p` from scope `sc`.
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.
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).
392 bool checkAccess(Loc loc
, Scope
*sc
, Package
*p
)
394 if (sc
->_module
== p
)
396 for (; sc
; sc
= sc
->enclosing
)
398 if (sc
->scopesym
&& sc
->scopesym
->isPackageAccessible(p
, Prot(PROTprivate
)))
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
);
405 deprecation(loc
, "%s %s is not accessible here", p
->kind(), name
);
410 * Check whether symbols `s` is visible in `mod`.
413 * mod = lookup origin
414 * s = symbol to check for visibility
415 * Returns: true if s is visible in mod
417 bool symbolIsVisible(Module
*mod
, Dsymbol
*s
)
419 // should sort overloads by ascending protection instead of iterating here
420 s
= mostVisibleOverload(s
);
422 switch (s
->prot().kind
)
427 return false; // no access
429 return s
->getAccessModule() == mod
;
431 return s
->getAccessModule() == mod
|| hasPackageAccess(mod
, s
);
433 return s
->getAccessModule() == mod
;
443 * Same as above, but determines the lookup module from symbols `origin`.
445 bool symbolIsVisible(Dsymbol
*origin
, Dsymbol
*s
)
447 return symbolIsVisible(origin
->getAccessModule(), s
);
451 * Same as above but also checks for protected symbols visible from scope `sc`.
452 * Used for qualified name lookup.
456 * s = symbol to check for visibility
457 * Returns: true if s is visible by origin
459 bool symbolIsVisible(Scope
*sc
, Dsymbol
*s
)
461 s
= mostVisibleOverload(s
);
463 switch (s
->prot().kind
)
468 return false; // no access
470 return sc
->_module
== s
->getAccessModule();
472 return sc
->_module
== s
->getAccessModule() || hasPackageAccess(sc
->_module
, s
);
474 return hasProtectedAccess(sc
, s
);
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.
489 static Dsymbol
*mostVisibleOverload(Dsymbol
*s
)
491 if (!s
->isOverloadable())
494 Dsymbol
*next
= NULL
;
496 Dsymbol
*mostVisible
= s
;
500 // private void func(int) {}
501 if (FuncDeclaration
*fd
= s
->isFuncDeclaration())
503 // template temp(T) {}
504 // private template temp(T:int) {}
505 else if (TemplateDeclaration
*td
= s
->isTemplateDeclaration())
507 // alias common = mod1.func1;
508 // alias common = mod2.func2;
509 else if (FuncAliasDeclaration
*fa
= s
->isFuncAliasDeclaration())
511 // alias common = mod1.templ1;
512 // alias common = mod2.templ2;
513 else if (OverDeclaration
*od
= s
->isOverDeclaration())
516 // private void name(int) {}
517 else if (AliasDeclaration
*ad
= s
->isAliasDeclaration())
519 if (!ad
->isOverloadable())
521 //printf("Non overloadable Aliasee in overload list\n");
524 // Yet unresolved aliases store overloads in overnext.
525 if (ad
->semanticRun
< PASSsemanticdone
)
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
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.
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.
543 Dsymbol
*aliasee
= ad
->toAlias();
544 if (aliasee
->isFuncAliasDeclaration() || aliasee
->isOverDeclaration())
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.
554 //printf("Unresolved overload of alias\n");
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
568 if (next
&& mostVisible
->prot().isMoreRestrictiveThan(next
->prot()))