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:
parent
19b826011e
commit
36e4ae3e57
|
@ -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);
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue