Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
------------------------------------------------------------------------ r233984 | ericwf | 2015-04-02 16:26:37 -0700 (Thu, 02 Apr 2015) | 22 lines [libcxxabi] Fix multi-level pointer conversions and pointer to member conversion detection. Summary: Currently there are bugs in out detection of multi-level pointer conversions and pointer to member conversions. This patch fixes the following issues. * Allow multi-level pointers with different nested qualifiers. * Allow multi-level mixed pointers to objects and pointers to members with different nested qualifiers. * Allow conversions from `int Base::*` to `int Derived::*` but only for non-nested pointers. There is still some work that needs to be done to clean this patch up but I want to get some input on it. Open questions: * Does `__pointer_to_member_type_info::can_catch(...)` need to adjust the pointer if a base to derived conversion is performed? Reviewers: danalbert, compnerd, mclow.lists Reviewed By: mclow.lists Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D8758 ------------------------------------------------------------------------ llvm-svn: 236862
- Loading branch information
1 parent
bdb73c2
commit 5b8be6a
Showing
3 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
//===--------------------- catch_pointer_nullptr.cpp ----------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is dual licensed under the MIT and the University of Illinois Open | ||
// Source Licenses. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include <cassert> | ||
#include <cstdlib> | ||
#include <iostream> | ||
|
||
// Roll our own assertion macro to get better error messages out of the tests. | ||
// In particular on systems that don't use __PRETTY_FUNCTION__ in assertions. | ||
#define my_assert(pred, msg) do_assert(pred, msg, __LINE__, __PRETTY_FUNCTION__) | ||
|
||
void do_assert(bool assert_passed, const char* msg, int line, const char* func) { | ||
if (assert_passed) return; | ||
std::cerr << __FILE__ << ":" << line << " " << func | ||
<< ": Assertion Failed `" << msg << "'\n\n"; | ||
std::abort(); | ||
} | ||
|
||
struct A {}; | ||
struct Base {}; | ||
struct Derived : public Base {}; | ||
|
||
template <class To> | ||
bool test_conversion(To) { return true; } | ||
|
||
template <class To> | ||
bool test_conversion(...) { return false; } | ||
|
||
template <class Pointer> | ||
struct CreatePointer { | ||
Pointer operator()() const { | ||
return (Pointer)0; | ||
} | ||
}; | ||
|
||
template <class Tp> | ||
struct CreatePointer<Tp*> { | ||
Tp* operator()() const { | ||
return (Tp*)42; | ||
} | ||
}; | ||
|
||
template <class Throw, class Catch> | ||
void catch_pointer_test() { | ||
Throw throw_ptr = CreatePointer<Throw>()(); | ||
// Use the compiler to determine if the exception of type Throw can be | ||
// implicitly converted to type Catch. | ||
const bool can_convert = test_conversion<Catch>(throw_ptr); | ||
try { | ||
throw throw_ptr; | ||
assert(false); | ||
} catch (Catch catch_ptr) { | ||
Catch catch2 = CreatePointer<Catch>()(); | ||
my_assert(can_convert, "non-convertible type incorrectly caught"); | ||
my_assert(catch_ptr == catch2, | ||
"Thrown pointer does not match caught ptr"); | ||
} catch (...) { | ||
my_assert(!can_convert, "convertible type incorrectly not caught"); | ||
} | ||
} | ||
|
||
// Generate CV qualified pointer typedefs. | ||
template <class Tp, bool First = false> | ||
struct TestTypes { | ||
typedef Tp* Type; | ||
typedef Tp const* CType; | ||
typedef Tp volatile* VType; | ||
typedef Tp const volatile* CVType; | ||
}; | ||
|
||
// Special case for cv-qualifying a pointer-to-member without adding an extra | ||
// pointer to it. | ||
template <class Member, class Class> | ||
struct TestTypes<Member Class::*, true> { | ||
typedef Member (Class::*Type); | ||
typedef const Member (Class::*CType); | ||
typedef volatile Member (Class::*VType); | ||
typedef const volatile Member (Class::*CVType); | ||
}; | ||
|
||
template <class Throw, class Catch, int level, bool first = false> | ||
struct generate_tests_imp { | ||
typedef TestTypes<Throw, first> ThrowTypes; | ||
typedef TestTypes<Catch, first> CatchTypes; | ||
void operator()() { | ||
typedef typename ThrowTypes::Type Type; | ||
typedef typename ThrowTypes::CType CType; | ||
typedef typename ThrowTypes::VType VType; | ||
typedef typename ThrowTypes::CVType CVType; | ||
|
||
run_catch_tests<Type>(); | ||
run_catch_tests<CType>(); | ||
run_catch_tests<VType>(); | ||
run_catch_tests<CVType>(); | ||
} | ||
|
||
template <class ThrowTp> | ||
void run_catch_tests() { | ||
typedef typename CatchTypes::Type Type; | ||
typedef typename CatchTypes::CType CType; | ||
typedef typename CatchTypes::VType VType; | ||
typedef typename CatchTypes::CVType CVType; | ||
|
||
catch_pointer_test<ThrowTp, Type>(); | ||
catch_pointer_test<ThrowTp, CType>(); | ||
catch_pointer_test<ThrowTp, VType>(); | ||
catch_pointer_test<ThrowTp, CVType>(); | ||
|
||
generate_tests_imp<ThrowTp, Type, level-1>()(); | ||
generate_tests_imp<ThrowTp, CType, level-1>()(); | ||
generate_tests_imp<ThrowTp, VType, level-1>()(); | ||
generate_tests_imp<ThrowTp, CVType, level-1>()(); | ||
} | ||
}; | ||
|
||
template <class Throw, class Catch, bool first> | ||
struct generate_tests_imp<Throw, Catch, 0, first> { | ||
void operator()() { | ||
catch_pointer_test<Throw, Catch>(); | ||
} | ||
}; | ||
|
||
template <class Throw, class Catch, int level> | ||
struct generate_tests : generate_tests_imp<Throw, Catch, level, true> {}; | ||
|
||
int main() | ||
{ | ||
generate_tests<int, int, 3>()(); | ||
generate_tests<Base, Derived, 2>()(); | ||
generate_tests<Derived, Base, 2>()(); | ||
generate_tests<int, void, 2>()(); | ||
generate_tests<void, int, 2>()(); | ||
|
||
generate_tests<int A::*, int A::*, 3>()(); | ||
generate_tests<int A::*, void, 2>()(); | ||
generate_tests<void, int A::*, 2>()(); | ||
generate_tests<int Base::*, int Derived::*, 2>()(); | ||
generate_tests<int Derived::*, int Base::*, 2>()(); | ||
} |