From: John McCall Date: Sat, 27 Mar 2010 06:55:49 +0000 (+0000) Subject: Accumulate all functions and classes that the effective context is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2cc2675d426af23476a9722c08c1b6c5266bd653;p=clang 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. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99709 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 4cfd99d5c5..9ceb17cd0f 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -53,32 +53,38 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, namespace { struct EffectiveContext { - EffectiveContext() : Inner(0), Function(0), Dependent(false) {} + EffectiveContext() : Inner(0), Dependent(false) {} explicit EffectiveContext(DeclContext *DC) : Inner(DC), Dependent(DC->isDependentContext()) { - if (isa(DC)) - DC = cast(DC)->getDeclContext(); - - if (isa(DC)) { - Function = cast(DC)->getCanonicalDecl(); - DC = Function->getDeclContext(); - } else - Function = 0; - // 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. - // This implies that the privileges of nesting are transitive. - while (isa(DC)) { - CXXRecordDecl *Record = cast(DC)->getCanonicalDecl(); - Records.push_back(Record); - DC = Record->getDeclContext(); + // 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(DC)) { + CXXRecordDecl *Record = cast(DC)->getCanonicalDecl(); + Records.push_back(Record); + DC = Record->getDeclContext(); + } else if (isa(DC)) { + FunctionDecl *Function = cast(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::const_iterator record_iterator; DeclContext *Inner; + llvm::SmallVector Functions; llvm::SmallVector Records; - FunctionDecl *Function; bool Dependent; }; } @@ -291,16 +297,18 @@ static Sema::AccessResult MatchesFriend(Sema &S, static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, FunctionDecl *Friend) { - if (!EC.Function) - return Sema::AR_inaccessible; + Sema::AccessResult OnFailure = Sema::AR_inaccessible; - if (Friend == EC.Function) - return Sema::AR_accessible; + for (llvm::SmallVectorImpl::const_iterator + 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)) - return Sema::AR_dependent; + if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) + OnFailure = Sema::AR_dependent; + } - return Sema::AR_inaccessible; + return OnFailure; } /// Determines whether the given friend function template matches @@ -308,21 +316,29 @@ static Sema::AccessResult MatchesFriend(Sema &S, static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, FunctionTemplateDecl *Friend) { - if (!EC.Function) return Sema::AR_inaccessible; + if (EC.Functions.empty()) return Sema::AR_inaccessible; - FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); - if (!FTD) - FTD = EC.Function->getDescribedFunctionTemplate(); - if (!FTD) - return Sema::AR_inaccessible; + Sema::AccessResult OnFailure = Sema::AR_inaccessible; - if (Friend == FTD->getCanonicalDecl()) - return Sema::AR_accessible; + for (llvm::SmallVectorImpl::const_iterator + I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { - if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) - return Sema::AR_dependent; + FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); + 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 diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 4da9eef25d..0ef6e3abfb 100644 --- a/test/CXX/class.access/p4.cpp +++ b/test/CXX/class.access/p4.cpp @@ -295,3 +295,17 @@ namespace test11 { B::~B() {}; } + +namespace test12 { + class A { + int x; + + void foo() { + class Local { + int foo(A *a) { + return a->x; + } + }; + } + }; +}