diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1798,6 +1798,8 @@ "lookup from the current scope refers here">; def err_qualified_member_nonclass : Error< "qualified member access refers to a member in %0">; +def err_qualified_member_not_base : Error< + "%0 is not a base of %1">; def err_incomplete_member_access : Error< "member access into incomplete type %0">; def err_incomplete_type : Error< diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -680,6 +680,22 @@ << DC << SS.getRange(); return true; } + // fix bug #54406 + // Per [class.access.base]/6, this example is ill-formed: + // struct A { + // int m; + // } a; + // struct B : A {}; + // int n = a.B::m; + if (BaseExpr && isa(DC) && isa(RDecl)) { + CXXRecordDecl *SRecord = cast(DC)->getCanonicalDecl(); + CXXRecordDecl *RRecord = cast(RDecl)->getCanonicalDecl(); + if (SRecord != RRecord && RRecord->isProvablyNotDerivedFrom(SRecord)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_not_base) + << DC << RDecl << SS.getRange(); + return true; + } + } } // The record definition is complete, now look up the member. diff --git a/clang/test/CXX/class.access/class.protected/p1.cpp b/clang/test/CXX/class.access/class.protected/p1.cpp --- a/clang/test/CXX/class.access/class.protected/p1.cpp +++ b/clang/test/CXX/class.access/class.protected/p1.cpp @@ -323,31 +323,32 @@ namespace test9 { class A { // expected-note {{member is declared here}} - protected: int foo(); // expected-note 4 {{declared}} expected-note 3 {{can only access this member on an object of type}} expected-note 2 {{member is declared here}} + protected: int foo(); // expected-note 2 {{can only access this member on an object of type 'test9::D'}} \ + // expected-note 2 {{member is declared here}} }; class B : public A { // expected-note {{member is declared here}} friend class D; }; - class C : protected B { // expected-note {{declared}} \ - // expected-note 7 {{constrained}} + class C : protected B { // expected-note 5 {{constrained by protected inheritance here}} expected-note {{declared protected here}} + }; class D : public A { static void test(A &a) { a.foo(); // expected-error {{'foo' is a protected member}} a.A::foo(); // expected-error {{'foo' is a protected member}} - a.B::foo(); // expected-error {{'foo' is a protected member}} - a.C::foo(); // expected-error {{'foo' is a protected member}} - a.D::foo(); // expected-error {{'foo' is a protected member}} + a.B::foo(); // expected-error {{'test9::B' is not a base of 'A'}} + a.C::foo(); // expected-error {{'test9::C' is not a base of 'A'}} + a.D::foo(); // expected-error {{'test9::D' is not a base of 'A'}} } static void test(B &b) { b.foo(); b.A::foo(); b.B::foo(); // accessible as named in A - b.C::foo(); // expected-error {{'foo' is a protected member}} + b.C::foo(); // expected-error {{'test9::C' is not a base of 'B'}} } static void test(C &c) { @@ -362,8 +363,8 @@ static void test(D &d) { d.foo(); d.A::foo(); - d.B::foo(); - d.C::foo(); // expected-error {{'foo' is a protected member}} + d.B::foo(); // expected-error {{'test9::B' is not a base of 'D'}} + d.C::foo(); // expected-error {{'test9::C' is not a base of 'D'}} } }; } diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -477,7 +477,7 @@ namespace dr141 { // dr141: yes template void f(); - template struct S { int n; }; // expected-note {{'::dr141::S::n' declared here}} + template struct S { int n; }; struct A : S { template void f(); template struct S {}; @@ -485,7 +485,7 @@ struct B : S {} b; void g() { a.f(); - (void)a.S::n; // expected-error {{no member named 'n' in 'dr141::A::S'; did you mean '::dr141::S::n'?}} + (void)a.S::n; // expected-error {{'dr141::A::S' is not a base of 'A'}} #if __cplusplus < 201103L // expected-error@-2 {{ambiguous}} // expected-note@-11 {{lookup from the current scope}} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp @@ -30,7 +30,7 @@ decltype(outer::middle::inner()) a; void scope() { - a.decltype(outer::middle())::mfunc(); // expected-error{{'PR10127::outer::middle::mfunc' is not a member of class 'decltype(outer::middle::inner())'}} + a.decltype(outer::middle())::mfunc(); // expected-error{{PR10127::outer::middle' is not a base of 'inner'}} a.decltype(outer::middle::inner())::func(); a.decltype(outer::middle())::inner::func(); a.decltype(outer())::middle::inner::func(); diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp --- a/clang/test/SemaCXX/member-expr.cpp +++ b/clang/test/SemaCXX/member-expr.cpp @@ -117,8 +117,8 @@ void f(Y *y) { y->N::X1; // expected-error{{'rdar8231724::N::X1' is not a member of class 'rdar8231724::Y'}} - y->Z::n; // expected-error{{'rdar8231724::Z::n' is not a member of class 'rdar8231724::Y'}} - y->template Z::n; // expected-error{{'rdar8231724::Z::n' is not a member of class 'rdar8231724::Y'}} + y->Z::n; // expected-error{{'rdar8231724::Z' is not a base of 'Y'}} + y->template Z::n; // expected-error{{'rdar8231724::Z' is not a base of 'Y'}} #if __cplusplus <= 199711L // C++03 or earlier modes // expected-warning@-2{{'template' keyword outside of a template}} #endif diff --git a/clang/test/SemaCXX/qual-id-test.cpp b/clang/test/SemaCXX/qual-id-test.cpp --- a/clang/test/SemaCXX/qual-id-test.cpp +++ b/clang/test/SemaCXX/qual-id-test.cpp @@ -54,7 +54,7 @@ a.A::sub::x(); a.A::B::base::x(); - a.bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}} + a.bad::x(); // expected-error{{'bad' is not a base of 'sub'}} a->foo(); a->member::foo(); @@ -75,7 +75,7 @@ a->A::sub::x(); a->A::B::base::x(); - a->bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}} + a->bad::x(); // expected-error{{'bad' is not a base of 'sub'}} (*a)->foo(); (*a)->member::foo(); @@ -119,7 +119,7 @@ a.A::B::base::x(); a->A::member::foo(); - a.bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}} + a.bad::x(); // expected-error{{'bad' is not a base of 'sub'}} } void test_fun5() { diff --git a/clang/test/SemaTemplate/typo-dependent-name.cpp b/clang/test/SemaTemplate/typo-dependent-name.cpp --- a/clang/test/SemaTemplate/typo-dependent-name.cpp +++ b/clang/test/SemaTemplate/typo-dependent-name.cpp @@ -37,9 +37,9 @@ bool f(T other) { // We can determine that 'inner' does not exist at parse time, so can // perform typo correction in this case. - return this->inner::z; // expected-error {{no template named 'inner' in 'Y'; did you mean 'Inner'?}} + return this->inner::z; // expected-error {{Y::Inner<0>' is not a base of 'Y'}} expected-error {{no template named 'inner' in 'Y'; did you mean 'Inner'?}} } }; struct Q { constexpr operator int() { return 0; } }; -void use_y(Y x) { x.f(Q()); } +void use_y(Y x) { x.f(Q()); } // expected-note {{in instantiation of member function 'Y::f' requested here}}