]>
git.ipfire.org Git - thirdparty/gcc.git/blob - 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
10 #include "root/dsystem.h"
11 #include "root/root.h"
12 #include "root/rmem.h"
16 #include "aggregate.h"
22 #include "declaration.h"
23 #include "aggregate.h"
24 #include "expression.h"
28 /* Code to do access checks
31 bool hasPackageAccess(Scope
*sc
, Dsymbol
*s
);
32 bool hasPackageAccess(Module
*mod
, Dsymbol
*s
);
33 bool hasPrivateAccess(AggregateDeclaration
*ad
, Dsymbol
*smember
);
34 bool isFriendOf(AggregateDeclaration
*ad
, AggregateDeclaration
*cd
);
35 static Dsymbol
*mostVisibleOverload(Dsymbol
*s
);
37 /****************************************
38 * Return Prot access for Dsymbol smember in this declaration.
40 Prot
getAccess(AggregateDeclaration
*ad
, Dsymbol
*smember
)
42 Prot access_ret
= Prot(PROTnone
);
44 assert(ad
->isStructDeclaration() || ad
->isClassDeclaration());
45 if (smember
->toParent() == ad
)
47 access_ret
= smember
->prot();
49 else if (smember
->isDeclaration()->isStatic())
51 access_ret
= smember
->prot();
53 if (ClassDeclaration
*cd
= ad
->isClassDeclaration())
55 for (size_t i
= 0; i
< cd
->baseclasses
->dim
; i
++)
57 BaseClass
*b
= (*cd
->baseclasses
)[i
];
59 Prot access
= getAccess(b
->sym
, smember
);
66 access_ret
= Prot(PROTnone
); // private members of base class not accessible
73 // If access is to be tightened
74 if (PROTpublic
< access
.kind
)
75 access
= Prot(PROTpublic
);
77 // Pick path with loosest access
78 if (access_ret
.isMoreRestrictiveThan(access
))
91 /********************************************************
92 * Helper function for checkAccess()
94 * false is not accessible
97 static bool isAccessible(
100 AggregateDeclaration
*dthis
,
101 AggregateDeclaration
*cdscope
)
105 if (hasPrivateAccess(dthis
, sfunc
) ||
106 isFriendOf(dthis
, cdscope
))
108 if (smember
->toParent() == dthis
)
111 if (ClassDeclaration
*cdthis
= dthis
->isClassDeclaration())
113 for (size_t i
= 0; i
< cdthis
->baseclasses
->dim
; i
++)
115 BaseClass
*b
= (*cdthis
->baseclasses
)[i
];
116 Prot access
= getAccess(b
->sym
, smember
);
117 if (access
.kind
>= PROTprotected
||
118 isAccessible(smember
, sfunc
, b
->sym
, cdscope
))
127 if (smember
->toParent() != dthis
)
129 if (ClassDeclaration
*cdthis
= dthis
->isClassDeclaration())
131 for (size_t i
= 0; i
< cdthis
->baseclasses
->dim
; i
++)
133 BaseClass
*b
= (*cdthis
->baseclasses
)[i
];
134 if (isAccessible(smember
, sfunc
, b
->sym
, cdscope
))
143 /*******************************
144 * Do access check for member of this class, this class being the
145 * type of the 'this' pointer used to access smember.
146 * Returns true if the member is not accessible.
148 bool checkAccess(AggregateDeclaration
*ad
, Loc loc
, Scope
*sc
, Dsymbol
*smember
)
150 FuncDeclaration
*f
= sc
->func
;
151 AggregateDeclaration
*cdscope
= sc
->getStructClassScope();
153 Dsymbol
*smemberparent
= smember
->toParent();
154 if (!smemberparent
|| !smemberparent
->isAggregateDeclaration())
156 return false; // then it is accessible
159 // BUG: should enable this check
160 //assert(smember->parent->isBaseOf(this, NULL));
164 if (smemberparent
== ad
)
166 access
= smember
->prot();
167 result
= access
.kind
>= PROTpublic
||
168 hasPrivateAccess(ad
, f
) ||
169 isFriendOf(ad
, cdscope
) ||
170 (access
.kind
== PROTpackage
&& hasPackageAccess(sc
, smember
)) ||
171 ad
->getAccessModule() == sc
->_module
;
173 else if ((access
= getAccess(ad
, smember
)).kind
>= PROTpublic
)
177 else if (access
.kind
== PROTpackage
&& hasPackageAccess(sc
, ad
))
183 result
= isAccessible(smember
, f
, ad
, cdscope
);
187 ad
->error(loc
, "member %s is not accessible", smember
->toChars());
188 //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
189 // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
195 /****************************************
196 * Determine if this is the same or friend of cd.
198 bool isFriendOf(AggregateDeclaration
*ad
, AggregateDeclaration
*cd
)
203 // Friends if both are in the same module
204 //if (toParent() == cd->toParent())
205 if (cd
&& ad
->getAccessModule() == cd
->getAccessModule())
213 /****************************************
214 * Determine if scope sc has package level access to s.
216 bool hasPackageAccess(Scope
*sc
, Dsymbol
*s
)
218 return hasPackageAccess(sc
->_module
, s
);
221 bool hasPackageAccess(Module
*mod
, Dsymbol
*s
)
229 // no explicit package for protection, inferring most qualified one
230 for (; s
; s
= s
->parent
)
232 if (Module
*m
= s
->isModule())
234 DsymbolTable
*dst
= Package::resolve(m
->md
? m
->md
->packages
: NULL
, NULL
, NULL
);
236 Dsymbol
*s2
= dst
->lookup(m
->ident
);
238 Package
*p
= s2
->isPackage();
239 if (p
&& p
->isPackageMod())
245 else if ((pkg
= s
->isPackage()) != NULL
)
252 if (pkg
== mod
->parent
)
256 if (pkg
->isPackageMod() == mod
)
260 Dsymbol
* ancestor
= mod
->parent
;
261 for (; ancestor
; ancestor
= ancestor
->parent
)
273 /****************************************
274 * Determine if scope sc has protected level access to cd.
276 bool hasProtectedAccess(Scope
*sc
, Dsymbol
*s
)
278 if (ClassDeclaration
*cd
= s
->isClassMember()) // also includes interfaces
280 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
284 ClassDeclaration
*cd2
= scx
->scopesym
->isClassDeclaration();
285 if (cd2
&& cd
->isBaseOf(cd2
, NULL
))
289 return sc
->_module
== s
->getAccessModule();
292 /**********************************
293 * Determine if smember has access to private members of this declaration.
295 bool hasPrivateAccess(AggregateDeclaration
*ad
, Dsymbol
*smember
)
299 AggregateDeclaration
*cd
= NULL
;
300 Dsymbol
*smemberparent
= smember
->toParent();
302 cd
= smemberparent
->isAggregateDeclaration();
304 if (ad
== cd
) // smember is a member of this class
306 return true; // so we get private access
309 // If both are members of the same module, grant access
312 Dsymbol
*sp
= smember
->toParent();
313 if (sp
->isFuncDeclaration() && smember
->isFuncDeclaration())
318 if (!cd
&& ad
->toParent() == smember
->toParent())
322 if (!cd
&& ad
->getAccessModule() == smember
->getAccessModule())
330 /****************************************
331 * Check access to d for expression e.d
332 * Returns true if the declaration is not accessible.
334 bool checkAccess(Loc loc
, Scope
*sc
, Expression
*e
, Declaration
*d
)
336 if (sc
->flags
& SCOPEnoaccesscheck
)
339 if (d
->isUnitTestDeclaration())
341 // Unittests are always accessible.
346 if ((d
->prot().kind
== PROTprivate
&& d
->getAccessModule() != sc
->_module
) ||
347 (d
->prot().kind
== PROTpackage
&& !hasPackageAccess(sc
, d
)))
349 error(loc
, "%s %s is not accessible from module %s",
350 d
->kind(), d
->toPrettyChars(), sc
->_module
->toChars());
354 else if (e
->type
->ty
== Tclass
)
357 ClassDeclaration
*cd
= (ClassDeclaration
*)(((TypeClass
*)e
->type
)->sym
);
358 if (e
->op
== TOKsuper
)
360 ClassDeclaration
*cd2
= sc
->func
->toParent()->isClassDeclaration();
364 return checkAccess(cd
, loc
, sc
, d
);
366 else if (e
->type
->ty
== Tstruct
)
369 StructDeclaration
*cd
= (StructDeclaration
*)(((TypeStruct
*)e
->type
)->sym
);
370 return checkAccess(cd
, loc
, sc
, d
);
375 /****************************************
376 * Check access to package/module `p` from scope `sc`.
379 * loc = source location for issued error message
380 * sc = scope from which to access to a fully qualified package name
381 * p = the package/module to check access for
382 * Returns: true if the package is not accessible.
384 * Because a global symbol table tree is used for imported packages/modules,
385 * access to them needs to be checked based on the imports in the scope chain
386 * (see Bugzilla 313).
389 bool checkAccess(Loc loc
, Scope
*sc
, Package
*p
)
391 if (sc
->_module
== p
)
393 for (; sc
; sc
= sc
->enclosing
)
395 if (sc
->scopesym
&& sc
->scopesym
->isPackageAccessible(p
, Prot(PROTprivate
)))
398 const char *name
= p
->toPrettyChars();
399 if (p
->isPkgMod
== PKGmodule
|| p
->isModule())
400 deprecation(loc
, "%s %s is not accessible here, perhaps add 'static import %s;'", p
->kind(), name
, name
);
402 deprecation(loc
, "%s %s is not accessible here", p
->kind(), name
);
407 * Check whether symbols `s` is visible in `mod`.
410 * mod = lookup origin
411 * s = symbol to check for visibility
412 * Returns: true if s is visible in mod
414 bool symbolIsVisible(Module
*mod
, Dsymbol
*s
)
416 // should sort overloads by ascending protection instead of iterating here
417 s
= mostVisibleOverload(s
);
419 switch (s
->prot().kind
)
424 return false; // no access
426 return s
->getAccessModule() == mod
;
428 return s
->getAccessModule() == mod
|| hasPackageAccess(mod
, s
);
430 return s
->getAccessModule() == mod
;
440 * Same as above, but determines the lookup module from symbols `origin`.
442 bool symbolIsVisible(Dsymbol
*origin
, Dsymbol
*s
)
444 return symbolIsVisible(origin
->getAccessModule(), s
);
448 * Same as above but also checks for protected symbols visible from scope `sc`.
449 * Used for qualified name lookup.
453 * s = symbol to check for visibility
454 * Returns: true if s is visible by origin
456 bool symbolIsVisible(Scope
*sc
, Dsymbol
*s
)
458 s
= mostVisibleOverload(s
);
460 switch (s
->prot().kind
)
465 return false; // no access
467 return sc
->_module
== s
->getAccessModule();
469 return sc
->_module
== s
->getAccessModule() || hasPackageAccess(sc
->_module
, s
);
471 return hasProtectedAccess(sc
, s
);
481 * Use the most visible overload to check visibility. Later perform an access
482 * check on the resolved overload. This function is similar to overloadApply,
483 * but doesn't recurse nor resolve aliases because protection/visibility is an
484 * attribute of the alias not the aliasee.
486 static Dsymbol
*mostVisibleOverload(Dsymbol
*s
)
488 if (!s
->isOverloadable())
491 Dsymbol
*next
= NULL
;
493 Dsymbol
*mostVisible
= s
;
497 // private void func(int) {}
498 if (FuncDeclaration
*fd
= s
->isFuncDeclaration())
500 // template temp(T) {}
501 // private template temp(T:int) {}
502 else if (TemplateDeclaration
*td
= s
->isTemplateDeclaration())
504 // alias common = mod1.func1;
505 // alias common = mod2.func2;
506 else if (FuncAliasDeclaration
*fa
= s
->isFuncAliasDeclaration())
508 // alias common = mod1.templ1;
509 // alias common = mod2.templ2;
510 else if (OverDeclaration
*od
= s
->isOverDeclaration())
513 // private void name(int) {}
514 else if (AliasDeclaration
*ad
= s
->isAliasDeclaration())
516 if (!ad
->isOverloadable())
518 //printf("Non overloadable Aliasee in overload list\n");
521 // Yet unresolved aliases store overloads in overnext.
522 if (ad
->semanticRun
< PASSsemanticdone
)
526 /* This is a bit messy due to the complicated implementation of
527 * alias. Aliases aren't overloadable themselves, but if their
528 * Aliasee is overloadable they can be converted to an overloadable
531 * This is done by replacing the Aliasee w/ FuncAliasDeclaration
532 * (for functions) or OverDeclaration (for templates) which are
533 * simply overloadable aliases w/ weird names.
535 * Usually aliases should not be resolved for visibility checking
536 * b/c public aliases to private symbols are public. But for the
537 * overloadable alias situation, the Alias (_ad_) has been moved
538 * into it's own Aliasee, leaving a shell that we peel away here.
540 Dsymbol
*aliasee
= ad
->toAlias();
541 if (aliasee
->isFuncAliasDeclaration() || aliasee
->isOverDeclaration())
545 /* A simple alias can be at the end of a function or template overload chain.
546 * It can't have further overloads b/c it would have been
547 * converted to an overloadable alias.
551 //printf("Unresolved overload of alias\n");
558 // handled by overloadApply for unknown reason
559 assert(next
!= ad
); // should not alias itself
560 assert(next
!= fstart
); // should not alias the overload list itself
565 if (next
&& mostVisible
->prot().isMoreRestrictiveThan(next
->prot()))