aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaAccess.cpp44
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp5
-rw-r--r--test/CXX/class.access/p4.cpp32
3 files changed, 76 insertions, 5 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index c3a1e75210..2a150d7c03 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1008,9 +1008,51 @@ static void DiagnoseAccessPath(Sema &S,
TryDiagnoseProtectedAccess(S, EC, Entity))
return;
+ // Find an original declaration.
+ while (D->isOutOfLine()) {
+ NamedDecl *PrevDecl = 0;
+ if (isa<VarDecl>(D))
+ PrevDecl = cast<VarDecl>(D)->getPreviousDeclaration();
+ else if (isa<FunctionDecl>(D))
+ PrevDecl = cast<FunctionDecl>(D)->getPreviousDeclaration();
+ else if (isa<TypedefDecl>(D))
+ PrevDecl = cast<TypedefDecl>(D)->getPreviousDeclaration();
+ else if (isa<TagDecl>(D)) {
+ if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
+ break;
+ PrevDecl = cast<TagDecl>(D)->getPreviousDeclaration();
+ }
+ if (!PrevDecl) break;
+ D = PrevDecl;
+ }
+
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+ Decl *ImmediateChild;
+ if (D->getDeclContext() == DeclaringClass)
+ ImmediateChild = D;
+ else {
+ DeclContext *DC = D->getDeclContext();
+ while (DC->getParent() != DeclaringClass)
+ DC = DC->getParent();
+ ImmediateChild = cast<Decl>(DC);
+ }
+
+ // Check whether there's an AccessSpecDecl preceding this in the
+ // chain of the DeclContext.
+ bool Implicit = true;
+ for (CXXRecordDecl::decl_iterator
+ I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
+ I != E; ++I) {
+ if (*I == ImmediateChild) break;
+ if (isa<AccessSpecDecl>(*I)) {
+ Implicit = false;
+ break;
+ }
+ }
+
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
- << /*FIXME: not implicitly*/ 0;
+ << Implicit;
return;
}
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 277b70bee6..761643b7d7 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -258,13 +258,12 @@ namespace test7 {
namespace test8 {
class A {
typedef int I; // expected-note 4 {{declared private here}}
- static const I x = 0;
+ static const I x = 0; // expected-note {{implicitly declared private here}}
friend I f(I i);
template<typename T> friend I g(I i);
};
- // FIXME: This should be on line 264.
- const A::I A::x; // expected-note {{declared private here}}
+ const A::I A::x;
A::I f(A::I i = A::x) {}
template<typename T> A::I g(A::I i) {
T t;
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 92b41b030d..565fcefe65 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -201,7 +201,7 @@ namespace test4 {
// Implicit copy assignment operator uses.
namespace test5 {
class A {
- void operator=(const A &); // expected-note 2 {{declared private here}}
+ void operator=(const A &); // expected-note 2 {{implicitly declared private here}}
};
class Test1 { A a; }; // expected-error {{private member}}
@@ -458,3 +458,33 @@ namespace test19 {
// testing PR7281, earlier in this file.
void b(A* x) { throw x; }
}
+
+// PR7930
+namespace test20 {
+ class Foo {
+ Foo(); // expected-note {{implicitly declared private here}}
+ };
+ Foo::Foo() {}
+
+ void test() {
+ Foo a; // expected-error {{calling a private constructor}}
+ }
+}
+
+namespace test21 {
+ template <class T> class A {
+ void foo();
+ void bar();
+ class Inner; // expected-note {{implicitly declared private here}}
+ public:
+ void baz();
+ };
+ template <class T> class A<T>::Inner {};
+ class B {
+ template <class T> class A<T>::Inner;
+ };
+
+ void test() {
+ A<int>::Inner i; // expected-error {{'Inner' is a private member}}
+ }
+}