aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaAccess.cpp15
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp16
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp2
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 {};