diff options
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 15 | ||||
-rw-r--r-- | test/CXX/class.access/class.friend/p1.cpp | 16 | ||||
-rw-r--r-- | test/CXX/class.access/class.protected/p1.cpp | 2 |
3 files changed, 27 insertions, 6 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index ed72a5600b..58b1a51ae5 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -97,14 +97,19 @@ struct EffectiveContext { // functions (which can gain privileges through friendship), but we // take that as an oversight. while (true) { + // We want to add canonical declarations to the EC lists for + // simplicity of checking, but we need to walk up through the + // actual current DC chain. Otherwise, something like a local + // extern or friend which happens to be the canonical + // declaration will really mess us up. + if (isa<CXXRecordDecl>(DC)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); - Records.push_back(Record); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + Records.push_back(Record->getCanonicalDecl()); DC = Record->getDeclContext(); } else if (isa<FunctionDecl>(DC)) { - FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); - Functions.push_back(Function); - + FunctionDecl *Function = cast<FunctionDecl>(DC); + Functions.push_back(Function->getCanonicalDecl()); if (Function->getFriendObjectKind()) DC = Function->getLexicalDeclContext(); else diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp index 3d3c5f789a..19d94cfdd5 100644 --- a/test/CXX/class.access/class.friend/p1.cpp +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -356,3 +356,19 @@ namespace PR9103 { } }; } + +// PR13642. When computing the effective context, we were walking up +// the DC chain for the canonical decl, which is unfortunate if that's +// (e.g.) a friend declaration. +namespace test14 { + class A { + class B { // expected-note {{implicitly declared private here}} + static int i; + friend void c(); + }; + }; + + void c() { + A::B::i = 5; // expected-error {{'B' is a private member of 'test14::A'}} + } +} diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp index c9491e1196..132ff6176c 100644 --- a/test/CXX/class.access/class.protected/p1.cpp +++ b/test/CXX/class.access/class.protected/p1.cpp @@ -423,7 +423,7 @@ namespace test12 { // This friendship is not considered because a public member of A is // inaccessible in C. namespace test13 { - class A { protected: int foo(); }; // expected-note {{can only access this member on an object of type}} + class A { protected: int foo(); }; // expected-note {{declared protected here}} class B : private virtual A {}; class C : private B { friend void test(); }; class D : public virtual A {}; |