llvm/clang/lib/Sema/SemaAccess.cpp

//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides Sema routines for C++ access control semantics.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/STLForwardCompat.h"

usingnamespaceclang;
usingnamespacesema;

/// A copy of Sema's enum without AR_delayed.
enum AccessResult {};

bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
                                    NamedDecl *PrevMemberDecl,
                                    AccessSpecifier LexicalAS) {}

static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {}

namespace {
struct EffectiveContext {};

/// Like sema::AccessedEntity, but kindly lets us scribble all over
/// it.
struct AccessTarget : public AccessedEntity {};

}

/// Checks whether one class might instantiate to the other.
static bool MightInstantiateTo(const CXXRecordDecl *From,
                               const CXXRecordDecl *To) {}

/// Checks whether one class is derived from another, inclusively.
/// Properly indicates when it couldn't be determined due to
/// dependence.
///
/// This should probably be donated to AST or at least Sema.
static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
                                           const CXXRecordDecl *Target) {}


static bool MightInstantiateTo(Sema &S, DeclContext *Context,
                               DeclContext *Friend) {}

// Asks whether the type in 'context' can ever instantiate to the type
// in 'friend'.
static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {}

static bool MightInstantiateTo(Sema &S,
                               FunctionDecl *Context,
                               FunctionDecl *Friend) {}

static bool MightInstantiateTo(Sema &S,
                               FunctionTemplateDecl *Context,
                               FunctionTemplateDecl *Friend) {}

static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  const CXXRecordDecl *Friend) {}

static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  CanQualType Friend) {}

/// Determines whether the given friend class template matches
/// anything in the effective context.
static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  ClassTemplateDecl *Friend) {}

/// Determines whether the given friend function matches anything in
/// the effective context.
static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  FunctionDecl *Friend) {}

/// Determines whether the given friend function template matches
/// anything in the effective context.
static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  FunctionTemplateDecl *Friend) {}

/// Determines whether the given friend declaration matches anything
/// in the effective context.
static AccessResult MatchesFriend(Sema &S,
                                  const EffectiveContext &EC,
                                  FriendDecl *FriendD) {}

static AccessResult GetFriendKind(Sema &S,
                                  const EffectiveContext &EC,
                                  const CXXRecordDecl *Class) {}

namespace {

/// A helper class for checking for a friend which will grant access
/// to a protected instance member.
struct ProtectedFriendContext {};
}

/// Search for a class P that EC is a friend of, under the constraint
///   InstanceContext <= P
/// if InstanceContext exists, or else
///   NamingClass <= P
/// and with the additional restriction that a protected member of
/// NamingClass would have some natural access in P, which implicitly
/// imposes the constraint that P <= NamingClass.
///
/// This isn't quite the condition laid out in the standard.
/// Instead of saying that a notional protected member of NamingClass
/// would have to have some natural access in P, it says the actual
/// target has to have some natural access in P, which opens up the
/// possibility that the target (which is not necessarily a member
/// of NamingClass) might be more accessible along some path not
/// passing through it.  That's really a bad idea, though, because it
/// introduces two problems:
///   - Most importantly, it breaks encapsulation because you can
///     access a forbidden base class's members by directly subclassing
///     it elsewhere.
///   - It also makes access substantially harder to compute because it
///     breaks the hill-climbing algorithm: knowing that the target is
///     accessible in some base class would no longer let you change
///     the question solely to whether the base class is accessible,
///     because the original target might have been more accessible
///     because of crazy subclassing.
/// So we don't implement that.
static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
                                           const CXXRecordDecl *InstanceContext,
                                           const CXXRecordDecl *NamingClass) {}

static AccessResult HasAccess(Sema &S,
                              const EffectiveContext &EC,
                              const CXXRecordDecl *NamingClass,
                              AccessSpecifier Access,
                              const AccessTarget &Target) {}

/// Finds the best path from the naming class to the declaring class,
/// taking friend declarations into account.
///
/// C++0x [class.access.base]p5:
///   A member m is accessible at the point R when named in class N if
///   [M1] m as a member of N is public, or
///   [M2] m as a member of N is private, and R occurs in a member or
///        friend of class N, or
///   [M3] m as a member of N is protected, and R occurs in a member or
///        friend of class N, or in a member or friend of a class P
///        derived from N, where m as a member of P is public, private,
///        or protected, or
///   [M4] there exists a base class B of N that is accessible at R, and
///        m is accessible at R when named in class B.
///
/// C++0x [class.access.base]p4:
///   A base class B of N is accessible at R, if
///   [B1] an invented public member of B would be a public member of N, or
///   [B2] R occurs in a member or friend of class N, and an invented public
///        member of B would be a private or protected member of N, or
///   [B3] R occurs in a member or friend of a class P derived from N, and an
///        invented public member of B would be a private or protected member
///        of P, or
///   [B4] there exists a class S such that B is a base class of S accessible
///        at R and S is a base class of N accessible at R.
///
/// Along a single inheritance path we can restate both of these
/// iteratively:
///
/// First, we note that M1-4 are equivalent to B1-4 if the member is
/// treated as a notional base of its declaring class with inheritance
/// access equivalent to the member's access.  Therefore we need only
/// ask whether a class B is accessible from a class N in context R.
///
/// Let B_1 .. B_n be the inheritance path in question (i.e. where
/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
/// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the
/// closest accessible base in the path:
///   Access(a, b) = (* access on the base specifier from a to b *)
///   Merge(a, forbidden) = forbidden
///   Merge(a, private) = forbidden
///   Merge(a, b) = min(a,b)
///   Accessible(c, forbidden) = false
///   Accessible(c, private) = (R is c) || IsFriend(c, R)
///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
///   Accessible(c, public) = true
///   ACAB(n) = public
///   ACAB(i) =
///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
///     if Accessible(B_i, AccessToBase) then public else AccessToBase
///
/// B is an accessible base of N at R iff ACAB(1) = public.
///
/// \param FinalAccess the access of the "final step", or AS_public if
///   there is no final step.
/// \return null if friendship is dependent
static CXXBasePath *FindBestPath(Sema &S,
                                 const EffectiveContext &EC,
                                 AccessTarget &Target,
                                 AccessSpecifier FinalAccess,
                                 CXXBasePaths &Paths) {}

/// Given that an entity has protected natural access, check whether
/// access might be denied because of the protected member access
/// restriction.
///
/// \return true if a note was emitted
static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
                                       AccessTarget &Target) {}

/// We are unable to access a given declaration due to its direct
/// access control;  diagnose that.
static void diagnoseBadDirectAccess(Sema &S,
                                    const EffectiveContext &EC,
                                    AccessTarget &entity) {}

/// Diagnose the path which caused the given declaration or base class
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
                               const EffectiveContext &EC,
                               AccessTarget &entity) {}

static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
                              const EffectiveContext &EC,
                              AccessTarget &Entity) {}

/// MSVC has a bug where if during an using declaration name lookup,
/// the declaration found is unaccessible (private) and that declaration
/// was bring into scope via another using declaration whose target
/// declaration is accessible (public) then no error is generated.
/// Example:
///   class A {
///   public:
///     int f();
///   };
///   class B : public A {
///   private:
///     using A::f;
///   };
///   class C : public B {
///   private:
///     using B::f;
///   };
///
/// Here, B::f is private so this should fail in Standard C++, but
/// because B::f refers to A::f which is public MSVC accepts it.
static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
                                                 SourceLocation AccessLoc,
                                                 AccessTarget &Entity) {}

/// Determines whether the accessed entity is accessible.  Public members
/// have been weeded out by this point.
static AccessResult IsAccessible(Sema &S,
                                 const EffectiveContext &EC,
                                 AccessTarget &Entity) {}

static void DelayDependentAccess(Sema &S,
                                 const EffectiveContext &EC,
                                 SourceLocation Loc,
                                 const AccessTarget &Entity) {}

/// Checks access to an entity from the given effective context.
static AccessResult CheckEffectiveAccess(Sema &S,
                                         const EffectiveContext &EC,
                                         SourceLocation Loc,
                                         AccessTarget &Entity) {}

static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
                                      AccessTarget &Entity) {}

void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {}

void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
                        const MultiLevelTemplateArgumentList &TemplateArgs) {}

Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
                                                     DeclAccessPair Found) {}

Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
                                                     DeclAccessPair Found) {}

bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
                                         DeclAccessPair Found,
                                         QualType ObjectType,
                                         SourceLocation Loc,
                                         const PartialDiagnostic &Diag) {}

Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
                                               CXXDestructorDecl *Dtor,
                                               const PartialDiagnostic &PDiag,
                                               QualType ObjectTy) {}

Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
                                                CXXConstructorDecl *Constructor,
                                                DeclAccessPair Found,
                                                const InitializedEntity &Entity,
                                                bool IsCopyBindingRefToTemp) {}

Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
                                                CXXConstructorDecl *Constructor,
                                                DeclAccessPair Found,
                                                const InitializedEntity &Entity,
                                                const PartialDiagnostic &PD) {}

Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
                                               SourceRange PlacementRange,
                                               CXXRecordDecl *NamingClass,
                                               DeclAccessPair Found,
                                               bool Diagnose) {}

Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
                                           CXXRecordDecl *NamingClass,
                                           DeclAccessPair Found) {}

Sema::AccessResult
Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
                                         CXXRecordDecl *DecomposedClass,
                                         DeclAccessPair Field) {}

Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
                                                   Expr *ObjectExpr,
                                                   const SourceRange &Range,
                                                   DeclAccessPair Found) {}

Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
                                                   Expr *ObjectExpr,
                                                   Expr *ArgExpr,
                                                   DeclAccessPair Found) {}

Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
                                                   Expr *ObjectExpr,
                                                   ArrayRef<Expr *> ArgExprs,
                                                   DeclAccessPair FoundDecl) {}

Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {}

Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
                                                    DeclAccessPair Found) {}

Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
                                              QualType Base,
                                              QualType Derived,
                                              const CXXBasePath &Path,
                                              unsigned DiagID,
                                              bool ForceCheck,
                                              bool ForceUnprivileged) {}

void Sema::CheckLookupAccess(const LookupResult &R) {}

bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
                              QualType BaseType) {}