From: John McCall Date: Tue, 9 Feb 2010 00:57:12 +0000 (+0000) Subject: Reset the found-virtual-base state unless the *current* base produces a path, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed814cc4cd2bd4d32cbb4bfde3cc59ccae723a92;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95638 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 7208328692..7d9e553eaf 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -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; } } diff --git a/test/CXX/conv/conv.mem/p4.cpp b/test/CXX/conv/conv.mem/p4.cpp new file mode 100644 index 0000000000..d782cde25a --- /dev/null +++ b/test/CXX/conv/conv.mem/p4.cpp @@ -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; + } +}