summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaAccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaAccess.cpp')
-rw-r--r--lib/Sema/SemaAccess.cpp592
1 files changed, 451 insertions, 141 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 51f9e30..eca8bb4 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -16,6 +16,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
@@ -47,192 +49,500 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
-/// Find a class on the derivation path between Derived and Base that is
-/// inaccessible. If @p NoPrivileges is true, special access rights (members
-/// and friends) are not considered.
-const CXXBaseSpecifier *Sema::FindInaccessibleBase(
- QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
- Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(!Paths.isAmbiguous(Base) &&
- "Can't check base class access if set of paths is ambiguous");
- assert(Paths.isRecordingPaths() &&
- "Can't check base class access without recorded paths");
-
-
- const CXXBaseSpecifier *InaccessibleBase = 0;
-
- const CXXRecordDecl *CurrentClassDecl = 0;
- if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
- CurrentClassDecl = MD->getParent();
-
- for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
- Path != PathsEnd; ++Path) {
-
- bool FoundInaccessibleBase = false;
-
- for (CXXBasePath::const_iterator Element = Path->begin(),
- ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
- const CXXBaseSpecifier *Base = Element->Base;
-
- switch (Base->getAccessSpecifier()) {
- default:
- assert(0 && "invalid access specifier");
- case AS_public:
- // Nothing to do.
- break;
- case AS_private:
- // FIXME: Check if the current function/class is a friend.
- if (NoPrivileges || CurrentClassDecl != Element->Class)
- FoundInaccessibleBase = true;
- break;
- case AS_protected:
- // FIXME: Implement
- break;
- }
+namespace {
+struct EffectiveContext {
+ EffectiveContext() : Record(0), Function(0) {}
+
+ explicit EffectiveContext(DeclContext *DC) {
+ if (isa<FunctionDecl>(DC)) {
+ Function = cast<FunctionDecl>(DC);
+ DC = Function->getDeclContext();
+ } else
+ Function = 0;
+
+ if (isa<CXXRecordDecl>(DC))
+ Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ else
+ Record = 0;
+ }
+
+ bool isClass(const CXXRecordDecl *R) const {
+ return R->getCanonicalDecl() == Record;
+ }
+
+ CXXRecordDecl *Record;
+ FunctionDecl *Function;
+};
+}
+
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
+static Sema::AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ if (EC.isClass(Class))
+ return Sema::AR_accessible;
+
+ // FIXME: implement
+ return Sema::AR_inaccessible;
+}
- if (FoundInaccessibleBase) {
- InaccessibleBase = Base;
- break;
+/// Finds the best path from the naming class to the declaring class,
+/// taking friend declarations into account.
+///
+/// \return null if friendship is dependent
+static CXXBasePath *FindBestPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *Derived,
+ CXXRecordDecl *Base,
+ CXXBasePaths &Paths) {
+ // Derive the paths to the desired base.
+ bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ assert(isDerived && "derived class not actually derived from base");
+ (void) isDerived;
+
+ CXXBasePath *BestPath = 0;
+
+ // Derive the friend-modified access along each path.
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+
+ // Walk through the path backwards.
+ AccessSpecifier PathAccess = AS_public;
+ CXXBasePath::iterator I = PI->end(), E = PI->begin();
+ while (I != E) {
+ --I;
+
+ AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
+ if (BaseAccess != AS_public) {
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: BaseAccess = AS_public; break;
+ case Sema::AR_dependent: return 0;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
+ }
}
+
+ PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
}
- if (!FoundInaccessibleBase) {
- // We found a path to the base, our work here is done.
- return 0;
+ // Note that we modify the path's Access field to the
+ // friend-modified access.
+ if (BestPath == 0 || PathAccess < BestPath->Access) {
+ BestPath = &*PI;
+ BestPath->Access = PathAccess;
}
}
- assert(InaccessibleBase && "no path found, but no inaccessible base");
- return InaccessibleBase;
+ return BestPath;
}
-/// CheckBaseClassAccess - Check that a derived class can access its base class
-/// and report an error if it can't. [class.access.base]
-bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths &Paths, SourceLocation AccessLoc,
- DeclarationName Name) {
+/// Diagnose the path which caused the given declaration or base class
+/// to become inaccessible.
+static void DiagnoseAccessPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ CXXRecordDecl *DeclaringClass,
+ NamedDecl *D, AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ // We have to check against AS_private here in case Access is AS_none,
+ // indicating a non-public member of a private base class.
+ //
+ // DependentFriend should be impossible here.
+ if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_inaccessible: {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected)
+ << /*FIXME: not implicitly*/ 0;
+ return;
+ }
- if (!getLangOptions().AccessControl)
- return false;
- const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
- Derived, Base, Paths);
+ case Sema::AR_accessible: break;
- if (InaccessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
- << Derived << Base << Name;
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent/delayed not allowed");
+ return;
+ }
+ }
- AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
+ CXXBasePaths Paths;
+ CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
- // If there's no written access specifier, then the inheritance specifier
- // is implicitly private.
- if (AS == AS_none)
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_implicitly_private_here);
- else
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_specifier_here) << AS;
+ CXXBasePath::iterator I = Path.end(), E = Path.begin();
+ while (I != E) {
+ --I;
- return true;
+ const CXXBaseSpecifier *BS = I->Base;
+ AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+
+ // If this is public inheritance, or the derived class is a friend,
+ // skip this step.
+ if (BaseAccess == AS_public)
+ continue;
+
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_accessible: continue;
+ case Sema::AR_inaccessible: break;
+
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent friendship, should not be diagnosing");
+ }
+
+ // Check whether this base specifier is the tighest point
+ // constraining access. We have to check against AS_private for
+ // the same reasons as above.
+ if (BaseAccess == AS_private || BaseAccess >= Access) {
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (D) diagnostic = diag::note_access_constrained_by_path;
+ else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
+ else diagnostic = diag::note_access_constrained_by_path;
+
+ S.Diag(BS->getSourceRange().getBegin(), diagnostic)
+ << BS->getSourceRange()
+ << (BaseAccess == AS_protected)
+ << (BS->getAccessSpecifierAsWritten() == AS_none);
+ return;
+ }
}
- return false;
+ llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose the path which caused the given declaration to become
-/// inaccessible.
-static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- // Easy case: the decl's natural access determined its path access.
- if (Access == D->getAccess() || D->getAccess() == AS_private) {
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected);
- return;
+/// Diagnose an inaccessible class member.
+static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity) {
+ NamedDecl *D = Entity.getTargetDecl();
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+
+ if (isa<CXXConstructorDecl>(D)) {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
+ : diag::err_access_ctor_private);
+ S.Diag(Loc, DiagID)
+ << S.Context.getTypeDeclType(DeclaringClass);
+ } else {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
+ : diag::err_access_private);
+ S.Diag(Loc, DiagID)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(DeclaringClass);
}
+ DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+}
- // TODO: flesh this out
- S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
- << (unsigned) (Access == AS_protected);
+/// Diagnose an inaccessible hierarchy conversion.
+static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (ADK == Sema::ADK_covariance) {
+ S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
+ S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else {
+ S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ }
+ DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
+ Entity.getBaseClass(), 0, Access);
}
-/// Checks access to the given declaration in the current context.
-///
-/// \param R the means via which the access was made; must have a naming
-/// class set
-/// \param D the declaration accessed
-/// \param Access the best access along any inheritance path from the
-/// naming class to the declaration. AS_none means the path is impossible
-bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- assert(R.getNamingClass() && "performing access check without naming class");
+static void DiagnoseBadAccess(Sema &S,
+ SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (Entity.isMemberAccess())
+ DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
+ else
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+}
- // If the access path is public, it's accessible everywhere.
- if (Access == AS_public)
- return false;
- // Otherwise, derive the current class context.
- DeclContext *DC = CurContext;
- while (isa<CXXRecordDecl>(DC) &&
- cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
- DC = DC->getParent();
-
- CXXRecordDecl *CurRecord;
- if (isa<CXXRecordDecl>(DC))
- CurRecord = cast<CXXRecordDecl>(DC);
- else if (isa<CXXMethodDecl>(DC))
- CurRecord = cast<CXXMethodDecl>(DC)->getParent();
- else {
- Diag(R.getNameLoc(), diag::err_access_outside_class)
- << (Access == AS_protected);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+/// Try to elevate access using friend declarations. This is
+/// potentially quite expensive.
+static void TryElevateAccess(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity,
+ AccessSpecifier &Access) {
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
+ } else {
+ DeclaringClass = Entity.getBaseClass();
}
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+
+ // Adjust the declaration of the referred entity.
+ AccessSpecifier DeclAccess = AS_none;
+ if (Entity.isMemberAccess()) {
+ NamedDecl *Target = Entity.getTargetDecl();
+
+ DeclAccess = Target->getAccess();
+ if (DeclAccess != AS_public) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_accessible: DeclAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ }
+ }
+
+ if (DeclaringClass == NamingClass) {
+ Access = DeclAccess;
+ return;
+ }
+ }
+
+ assert(DeclaringClass != NamingClass);
- CXXRecordDecl *NamingClass = R.getNamingClass();
+ // Append the declaration's access if applicable.
+ CXXBasePaths Paths;
+ CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
+ DeclaringClass, Paths);
+ if (!Path) {
+ // FIXME: delay dependent friendship
+ return;
+ }
+
+ // Grab the access along the best path.
+ AccessSpecifier NewAccess = Path->Access;
+ if (Entity.isMemberAccess())
+ NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
+
+ assert(NewAccess <= Access && "access along best path worse than direct?");
+ Access = NewAccess;
+}
+
+/// Checks access to an entity from the given effective context.
+static Sema::AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ Sema::AccessedEntity const &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ AccessSpecifier Access = Entity.getAccess();
+ assert(Access != AS_public);
+
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
// This should be guaranteed by the fact that the decl has
// non-public access. If not, we should make it guaranteed!
NamingClass = cast<CXXRecordDecl>(NamingClass);
+ if (!EC.Record) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+ }
+
// White-list accesses from within the declaring class.
- if (Access != AS_none &&
- CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
- return false;
+ if (Access != AS_none && EC.isClass(NamingClass))
+ return Sema::AR_accessible;
+
+ // If the access is worse than 'protected', try to promote to it using
+ // friend declarations.
+ bool TriedElevation = false;
+ if (Access != AS_protected) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ TriedElevation = true;
+ }
// Protected access.
if (Access == AS_protected) {
// FIXME: implement [class.protected]p1
- if (CurRecord->isDerivedFrom(NamingClass))
- return false;
+ if (EC.Record->isDerivedFrom(NamingClass))
+ return Sema::AR_accessible;
- // FIXME: dependent classes
+ // FIXME: delay dependent classes
}
- // FIXME: friends
+ // We're about to reject; one last chance to promote access.
+ if (!TriedElevation) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ }
+
+ // Okay, that's it, reject it.
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+}
- // Okay, it's a bad access, reject it.
+static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK
+ = Sema::ADK_normal) {
+ // If the access path is public, it's accessible everywhere.
+ if (Entity.getAccess() == AS_public)
+ return Sema::AR_accessible;
+
+ // If we're currently parsing a top-level declaration, delay
+ // diagnostics. This is the only case where parsing a declaration
+ // can actually change our effective context for the purposes of
+ // access control.
+ if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
+ assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
+ S.DelayedDiagnostics.push_back(
+ Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
+ return Sema::AR_delayed;
+ }
-
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+ Loc, Entity, ADK);
+}
- if (Access == AS_protected) {
- Diag(R.getNameLoc(), diag::err_access_protected)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
- }
+void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+ // Pretend we did this from the context of the newly-parsed
+ // declaration.
+ EffectiveContext EC(Ctx->getDeclContext());
+
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+ DD.Triggered = true;
+}
+
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl || !E->getNamingClass())
+ return AR_accessible;
- assert(Access == AS_private || Access == AS_none);
- Diag(R.getNameLoc(), diag::err_access_private)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+ return CheckAccess(*this, E->getNameLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+/// Perform access-control checking on a previously-unresolved member
+/// access which has now been resolved to a member.
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ return CheckAccess(*this, E->getMemberLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *RT) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+ CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
+
+ AccessSpecifier Access = Dtor->getAccess();
+ if (Access == AS_public)
+ return AR_accessible;
+
+ return CheckAccess(*this, Loc,
+ AccessedEntity::makeMember(NamingClass, Access, Dtor));
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ return CheckAccess(*this, UseLoc,
+ AccessedEntity::makeMember(NamingClass, Access, Constructor));
+}
+
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ NamedDecl *MemberOperator,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
+ assert(RT && "found member operator but object expr not of record type");
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+
+ return CheckAccess(*this, OpLoc,
+ AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
+
+/// Checks access for a hierarchy conversion.
+///
+/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
+/// or a derived-to-base conversion (false)
+/// \param ForceCheck true if this check should be performed even if access
+/// control is disabled; some things rely on this for semantics
+/// \param ForceUnprivileged true if this check should proceed as if the
+/// context had no special privileges
+/// \param ADK controls the kind of diagnostics that are used
+Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base,
+ QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck,
+ bool ForceUnprivileged,
+ AccessDiagnosticsKind ADK) {
+ if (!ForceCheck && !getLangOptions().AccessControl)
+ return AR_accessible;
+
+ if (Path.Access == AS_public)
+ return AR_accessible;
+
+ // TODO: preserve the information about which types exactly were used.
+ CXXRecordDecl *BaseD, *DerivedD;
+ BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
+ BaseD, DerivedD,
+ Path.Access);
+
+ if (ForceUnprivileged)
+ return CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity, ADK);
+ return CheckAccess(*this, AccessLoc, Entity, ADK);
}
/// Checks access to all the declarations in the given result set.
-void Sema::CheckAccess(const LookupResult &R) {
+void Sema::CheckLookupAccess(const LookupResult &R) {
+ assert(getLangOptions().AccessControl
+ && "performing access check without access control");
+ assert(R.getNamingClass() && "performing access check without naming class");
+
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- CheckAccess(R, *I, I.getAccess());
+ if (I.getAccess() != AS_public)
+ CheckAccess(*this, R.getNameLoc(),
+ AccessedEntity::makeMember(R.getNamingClass(),
+ I.getAccess(), *I));
}
OpenPOWER on IntegriCloud