Reset the found-virtual-base state unless the *current* base produces a path,

not *any* base up to now has produced a path.  Fixes PR 6254.

I'll do the access-control part of this patch RSN.

llvm-svn: 95638
This commit is contained in:
John McCall 2010-02-09 00:57:12 +00:00
parent 89261502cb
commit 6f891400c2
2 changed files with 72 additions and 4 deletions

View File

@ -215,10 +215,13 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
Paths.ScratchPath.Access
= MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
}
// Track whether there's a path involving this specific base.
bool FoundPathThroughBase = false;
if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
// We've found a path that terminates at this base.
FoundPath = true;
FoundPath = FoundPathThroughBase = true;
if (Paths.isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
@ -240,7 +243,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// There is a path to a base class that meets the criteria. If we're
// not collecting paths or finding ambiguities, we're done.
FoundPath = true;
FoundPath = FoundPathThroughBase = true;
if (!Paths.isFindingAmbiguities())
return FoundPath;
}
@ -253,7 +256,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
}
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPath) {
if (SetVirtual && !FoundPathThroughBase) {
Paths.DetectedVirtual = 0;
}
}

View File

@ -0,0 +1,65 @@
// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
struct Base {
int data;
int method();
};
int (Base::*data_ptr) = &Base::data;
int (Base::*method_ptr)() = &Base::method;
namespace test0 {
struct Derived : Base {};
void test() {
int (Derived::*d) = data_ptr;
int (Derived::*m)() = method_ptr;
}
}
// FIXME: can't be inaccessible.
namespace test1 {
struct Derived : private Base {};
void test() {
int (Derived::*d) = data_ptr; // error
int (Derived::*m)() = method_ptr; // error
}
};
// Can't be ambiguous.
namespace test2 {
struct A : Base {};
struct B : Base {};
struct Derived : A, B {};
void test() {
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test2::Derived'}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test2::Derived'}}
}
}
// Can't be virtual.
namespace test3 {
struct Derived : virtual Base {};
void test() {
int (Derived::*d) = data_ptr; // expected-error {{conversion from pointer to member of class 'struct Base' to pointer to member of class 'struct test3::Derived' via virtual base 'struct Base' is not allowed}}
int (Derived::*m)() = method_ptr; // expected-error {{conversion from pointer to member of class 'struct Base' to pointer to member of class 'struct test3::Derived' via virtual base 'struct Base' is not allowed}}
}
}
// Can't be virtual even if there's a non-virtual path.
namespace test4 {
struct A : Base {};
struct Derived : Base, virtual A {};
void test() {
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test4::Derived'}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test4::Derived'}}
}
}
// PR6254: don't get thrown off by a virtual base.
namespace test5 {
struct A {};
struct Derived : Base, virtual A {};
void test() {
int (Derived::*d) = data_ptr;
int (Derived::*m)() = method_ptr;
}
}