From: John McCall Date: Wed, 20 Oct 2010 08:15:06 +0000 (+0000) Subject: Access control polish: drop the note on the original declaration and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa56a66abb61e9f42b48ae88e43328aba10c9148;p=clang Access control polish: drop the note on the original declaration and say 'implicitly' when it was implicit. Resolves PR 7930 and my peace of mind. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116916 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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(D)) + PrevDecl = cast(D)->getPreviousDeclaration(); + else if (isa(D)) + PrevDecl = cast(D)->getPreviousDeclaration(); + else if (isa(D)) + PrevDecl = cast(D)->getPreviousDeclaration(); + else if (isa(D)) { + if (isa(D) && cast(D)->isInjectedClassName()) + break; + PrevDecl = cast(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(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(*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 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 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 A { + void foo(); + void bar(); + class Inner; // expected-note {{implicitly declared private here}} + public: + void baz(); + }; + template class A::Inner {}; + class B { + template class A::Inner; + }; + + void test() { + A::Inner i; // expected-error {{'Inner' is a private member}} + } +}