Accumulate all functions and classes that the effective context is

nested within, and suddenly local classes start working.  Wouldn't be
necessary if I hadn't used local classes in Clang in the first place.
Or, well, wouldn't be necessary yet. :)

llvm-svn: 99709
This commit is contained in:
John McCall 2010-03-27 06:55:49 +00:00
parent 2f88d7d72c
commit 3dc81f77f6
2 changed files with 65 additions and 35 deletions

View File

@ -53,32 +53,38 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
namespace { namespace {
struct EffectiveContext { struct EffectiveContext {
EffectiveContext() : Inner(0), Function(0), Dependent(false) {} EffectiveContext() : Inner(0), Dependent(false) {}
explicit EffectiveContext(DeclContext *DC) explicit EffectiveContext(DeclContext *DC)
: Inner(DC), : Inner(DC),
Dependent(DC->isDependentContext()) { Dependent(DC->isDependentContext()) {
if (isa<EnumDecl>(DC))
DC = cast<EnumDecl>(DC)->getDeclContext();
if (isa<FunctionDecl>(DC)) {
Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
DC = Function->getDeclContext();
} else
Function = 0;
// C++ [class.access.nest]p1: // C++ [class.access.nest]p1:
// A nested class is a member and as such has the same access // A nested class is a member and as such has the same access
// rights as any other member. // rights as any other member.
// C++ [class.access]p2: // C++ [class.access]p2:
// A member of a class can also access all the names to which // A member of a class can also access all the names to which
// the class has access. // the class has access. A local class of a member function
// This implies that the privileges of nesting are transitive. // may access the same names that the member function itself
while (isa<CXXRecordDecl>(DC)) { // may access.
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); // This almost implies that the privileges of nesting are transitive.
Records.push_back(Record); // Technically it says nothing about the local classes of non-member
DC = Record->getDeclContext(); // 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();
}
} }
} }
@ -99,8 +105,8 @@ struct EffectiveContext {
typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
DeclContext *Inner; DeclContext *Inner;
llvm::SmallVector<FunctionDecl*, 4> Functions;
llvm::SmallVector<CXXRecordDecl*, 4> Records; llvm::SmallVector<CXXRecordDecl*, 4> Records;
FunctionDecl *Function;
bool Dependent; bool Dependent;
}; };
} }
@ -291,16 +297,18 @@ static Sema::AccessResult MatchesFriend(Sema &S,
static Sema::AccessResult MatchesFriend(Sema &S, static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC, const EffectiveContext &EC,
FunctionDecl *Friend) { FunctionDecl *Friend) {
if (!EC.Function) Sema::AccessResult OnFailure = Sema::AR_inaccessible;
return Sema::AR_inaccessible;
if (Friend == EC.Function) for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
return Sema::AR_accessible; I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (Friend == *I)
return Sema::AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, EC.Function, Friend)) if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
return Sema::AR_dependent; OnFailure = Sema::AR_dependent;
}
return Sema::AR_inaccessible; return OnFailure;
} }
/// Determines whether the given friend function template matches /// Determines whether the given friend function template matches
@ -308,21 +316,29 @@ static Sema::AccessResult MatchesFriend(Sema &S,
static Sema::AccessResult MatchesFriend(Sema &S, static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC, const EffectiveContext &EC,
FunctionTemplateDecl *Friend) { FunctionTemplateDecl *Friend) {
if (!EC.Function) return Sema::AR_inaccessible; if (EC.Functions.empty()) return Sema::AR_inaccessible;
FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); Sema::AccessResult OnFailure = Sema::AR_inaccessible;
if (!FTD)
FTD = EC.Function->getDescribedFunctionTemplate();
if (!FTD)
return Sema::AR_inaccessible;
if (Friend == FTD->getCanonicalDecl()) for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
return Sema::AR_accessible; I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
return Sema::AR_dependent; if (!FTD)
FTD = (*I)->getDescribedFunctionTemplate();
if (!FTD)
continue;
return Sema::AR_inaccessible; FTD = FTD->getCanonicalDecl();
if (Friend == FTD)
return Sema::AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
OnFailure = Sema::AR_dependent;
}
return OnFailure;
} }
/// Determines whether the given friend declaration matches anything /// Determines whether the given friend declaration matches anything

View File

@ -295,3 +295,17 @@ namespace test11 {
B::~B() {}; B::~B() {};
} }
namespace test12 {
class A {
int x;
void foo() {
class Local {
int foo(A *a) {
return a->x;
}
};
}
};
}