//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Sema routines for C++ access control semantics.
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
/// Returns true on error (when the previous member decl access specifier
/// is different from the new member decl access specifier).
bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS) {
if (!PrevMemberDecl) {
// Use the lexical access specifier.
MemberDecl->setAccess(LexicalAS);
return false;
}
// C++ [class.access.spec]p3: When a member is redeclared its access
// specifier must be same as its initial declaration.
if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
Diag(MemberDecl->getLocation(),
diag::err_class_redeclared_with_different_access)
<< MemberDecl << LexicalAS;
Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
<< PrevMemberDecl << PrevMemberDecl->getAccess();
MemberDecl->setAccess(LexicalAS);
return true;
}
MemberDecl->setAccess(PrevMemberDecl->getAccess());
return false;
}
namespace {
struct EffectiveContext {
EffectiveContext() : Inner(0), Dependent(false) {}
explicit EffectiveContext(DeclContext *DC)
: Inner(DC),
Dependent(DC->isDependentContext()) {
// C++ [class.access.nest]p1:
// A nested class is a member and as such has the same access
// rights as any other member.
// C++ [class.access]p2:
// A member of a class can also access all the names to which
// the class has access. A local class of a member function
// may access the same names that the member function itself
// may access.
// This almost implies that the privileges of nesting are transitive.
// Technically it says nothing about the local classes of non-member
// functions (which can gain privileges through friendship), but we
// take that as an oversight.
while (true) {
if (isa<CXXRecordDecl>(DC)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
Records.push_back(Record);
DC = Record->getDeclContext();
} else if (isa<FunctionDecl>(DC)) {
FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
Functions.push_back(Function);
DC = Function->getDeclContext();
} else if (DC->isFileContext()) {
break;
} else {
DC = DC->getParent();
}
}
}
bool isDependent() const { return Dependent; }
bool includesClass(const CXXRecordDecl *R) const {
R = R->getCanonicalDecl();
return std::find(Records.begin(), Records.end(), R)
!= Records.end();
}
/// Retrieves the innermost "useful" context. Can be null if we're
/// doing access-control without privileges.
DeclContext *getInnerContext() const {
return Inner;
}
typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
DeclContext *Inner;
llvm::SmallVector<FunctionDecl*, 4> Functions;
llvm::SmallVector<CXXRecordDecl*, 4> Records;
bool Dependent;
};
}
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
DeclContext *DC = D->getDeclContext();
// This can only happen at top: enum decls only "publish" their
// immediate members.
if (isa<EnumDecl>(DC))
DC = cast<EnumDecl>(DC)->getDeclContext();
CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
while (DeclaringClass->isAnonymousStructOrUnion())
DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
return DeclaringClass;
}
static bool MightInstantiateTo(Sema &S, DeclContext *Context,
DeclContext *Friend)