When creating an implicit member expression through a qualified-id, check that the class

named by the nested-name-specifier is same or base of the class in which the member expression appears.

It seems we also had an ill-formed test case, mon dieu! Fixes rdar://8576107.

llvm-svn: 129493
This commit is contained in:
Argyrios Kyrtzidis 2011-04-14 00:46:47 +00:00
parent 19b826011e
commit 36e4ae3e57
2 changed files with 26 additions and 9 deletions

View File

@ -1318,12 +1318,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Error_StaticContext;
}
CXXRecordDecl *
contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
// [class.mfct.non-static]p3:
// ...is used in the body of a non-static member function of class X,
// if name lookup (3.4.1) resolves the name in the id-expression to a
// non-static non-type member of some class C [...]
// ...if C is not X or a base class of X, the class member access expression
// is ill-formed.
if (R.getNamingClass() &&
contextClass != R.getNamingClass()->getCanonicalDecl() &&
contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
if (IsProvablyNotDerivedFrom(SemaRef,
cast<CXXMethodDecl>(DC)->getParent(),
Classes))
if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
return (hasNonInstance ? IMA_Mixed : IMA_Instance);

View File

@ -35,17 +35,22 @@ namespace test1 {
struct A {
void foo(Opaque1); // expected-note {{candidate}}
void foo(Opaque2); // expected-note {{candidate}}
void test();
};
struct B : A {
void test();
};
void A::test() {
B::foo(Opaque1());
B::foo(Opaque2());
B::foo(Opaque3()); // expected-error {{no matching member function}}
struct C1 : A { };
struct C2 : B { };
void B::test() {
A::foo(Opaque1());
A::foo(Opaque2());
A::foo(Opaque3()); // expected-error {{no matching member function}}
C1::foo(Opaque1()); // expected-error {{call to non-static member function without an object argument}}
C2::foo(Opaque1()); // expected-error {{call to non-static member function without an object argument}}
}
}