[cfe-commits] [libcxxabi] r148038 - in /libcxxabi/trunk: src/private_typeinfo.cpp test/dynamic_cast3.cpp

Howard Hinnant hhinnant at apple.com
Thu Jan 12 11:48:14 PST 2012


Author: hhinnant
Date: Thu Jan 12 13:48:14 2012
New Revision: 148038

URL: http://llvm.org/viewvc/llvm-project?rev=148038&view=rev
Log:
Fixed a couple of bugs, updated many comments, and am including a comprehensive test for when there are only 3 types in place.  I need to do something similar for 4 and maybe more types, but I'm not sure how comprehensive I can make the test at 4 and above types.

Added:
    libcxxabi/trunk/test/dynamic_cast3.cpp
Modified:
    libcxxabi/trunk/src/private_typeinfo.cpp

Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=148038&r1=148037&r2=148038&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Thu Jan 12 13:48:14 2012
@@ -62,6 +62,11 @@
 // __dynamic_cast notes:
 // Up or above refers to base classes and base objects.
 // Down or below refers to derived classes/objects.
+// There are two search algorithms, search1 and search2.
+// search1 is nothing but an optimization of search2 for a special case.
+// Take it away and things should still work correctly.
+// Both algorithms return 1 if the search should continue below the current node
+//    and 0 if the search should be aborted (because the answer is now known).
 
 // search1 is a search algorithm used by __dynamic_cast.
 // If a static_type is found
@@ -73,35 +78,13 @@
 // Else
 //     Continue search above and below this node.
 
-// __class_type_info::search1
-// There are no nodes to search above this node
-// Returns:  1 if search should be continued, otherwise 0
-int
-__class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
-                           int path_below) const
-{
-    if (this == info->static_type)
-    {
-        if (dynamic_ptr == info->static_ptr)
-        {
-            if (path_below == public_path)
-            {
-                info->path_dynamic_ptr_to_static_ptr = public_path;
-                return 0;
-            }
-            info->path_dynamic_ptr_to_static_ptr = not_public_path;
-        }
-    }
-    return 1;
-}
-
 // search2 is a search algorithm used by __dynamic_cast.
 // if this is a dst_type
-//     if this has already been classified then
+//     if this node has already been classified then
 //        If the path to get here is public, overwrite existing path_dynamic_ptr_to_dst_ptr.
-//     else we haven't been to this dst_type before.
+//     else we haven't been to this (ptr, dst_type) before.
 //        Record the path to get here in path_dynamic_ptr_to_dst_ptr.
-//        Is (static_ptr, static_type) above this dst_type?
+//        For each base is (static_ptr, static_type) above this dst_type?
 //           Yes:
 //             Record it as dst_ptr_leading_to_static_ptr and increment the
 //                number of such recordings.
@@ -110,6 +93,7 @@
 //           No:
 //             record it as dst_ptr_not_leading_to_static_ptr and increment
 //                 the number of such recordings.
+//             Continue searching both above and below this node.
 // else if this is a static_type
 //     if this is *our* static_type
 //        if we found it above a dst_type, record the path from the dst_type
@@ -119,6 +103,30 @@
 //     Continue searching only below this node
 // else 
 //     Continue searching above and below this node.
+
+// __class_type_info::search1
+// There are no nodes to search above this node
+int
+__class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                           int path_below) const
+{
+    if (this == info->static_type)
+    {
+        if (dynamic_ptr == info->static_ptr)
+        {
+            if (path_below == public_path)
+            {
+                info->path_dynamic_ptr_to_static_ptr = public_path;
+                return 0;
+            }
+            info->path_dynamic_ptr_to_static_ptr = not_public_path;
+        }
+    }
+    return 1;
+}
+
+// __class_type_info::search2
+// There are no nodes to search above this node
 int
 __class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
                            int path_below) const
@@ -160,6 +168,9 @@
 {
 }
 
+// __si_class_type_info::search1
+// There is one node to search above this node.  The path to it is public
+//  and dynamic_ptr needs no adjustment in moving to that node.
 int
 __si_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
                               int path_below) const
@@ -179,6 +190,9 @@
     return __base_type->search1(info, dynamic_ptr, path_below);
 }
 
+// __si_class_type_info::search2
+// There is one node to search above this node.  The path to it is public
+//  and dynamic_ptr needs no adjustment in moving to that node.
 int
 __si_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
                               int path_below) const
@@ -237,6 +251,11 @@
 {
 }
 
+// __vmi_class_type_info::search1
+// There are one or more nodes to search above this node.  The path to it
+//  may be public or not and the dynamic_ptr may need to be adjusted.  Both
+//  of these details are handled by a pseudo-node in __base_class_type_info
+//  which has no type associated with it.
 int
 __vmi_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
                                int path_below) const
@@ -263,21 +282,11 @@
     return 1;
 }
 
-int
-__base_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
-                                int path_below) const
-{
-    ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
-    if (__offset_flags & __virtual_mask)
-    {
-        char* vtable = *(char**)dynamic_ptr;
-        offset_to_base = (ptrdiff_t)vtable[offset_to_base];
-    }
-    return __base_type->search1(info, (char*)dynamic_ptr + offset_to_base,
-                                (__offset_flags & __public_mask) ? path_below :
-                                                                   not_public_path);
-}
-
+// __vmi_class_type_info::search2
+// There are one or more nodes to search above this node.  The path to it
+//  may be public or not and the dynamic_ptr may need to be adjusted.  Both
+//  of these details are handled by a pseudo-node in __base_class_type_info
+//  which has no type associated with it.
 int
 __vmi_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
                                int path_below) const
@@ -297,10 +306,10 @@
             for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
             {
                 info->above_dst_ptr = true;
-                int r = p->search2(info, dynamic_ptr, public_path);
+                // Only a dst_type can abort the search, and one can't be
+                //   above here.  So it is safe to ignore return.
+                (void)p->search2(info, dynamic_ptr, public_path);
                 info->above_dst_ptr = false;
-                if (r == 0)
-                    return 0;
                 if (info->found_static_ptr)
                 {
                     info->found_static_ptr = false;
@@ -339,6 +348,35 @@
     return 1;
 }
 
+// __base_class_type_info::search1
+// This is a psuedo-node which does nothing but adjust the path access and
+//  dynamic_ptr prior to calling the base node above.
+//  The dynamic_ptr adjustment depends upon whether or not this node is marked
+//     virtual.
+//  If the path up is public, no change is made to the path (it may already be
+//     marked private from below).  If the path up is private, it is forced so.
+int
+__base_class_type_info::search1(__dynamic_cast_info* info, const void* dynamic_ptr,
+                                int path_below) const
+{
+    ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+    if (__offset_flags & __virtual_mask)
+    {
+        char* vtable = *(char**)dynamic_ptr;
+        offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
+    }
+    return __base_type->search1(info, (char*)dynamic_ptr + offset_to_base,
+                                (__offset_flags & __public_mask) ? path_below :
+                                                                   not_public_path);
+}
+
+// __base_class_type_info::search2
+// This is a psuedo-node which does nothing but adjust the path access and
+//  dynamic_ptr prior to calling the base node above.
+//  The dynamic_ptr adjustment depends upon whether or not this node is marked
+//     virtual.
+//  If the path up is public, no change is made to the path (it may already be
+//     marked private from below).  If the path up is private, it is forced so.
 int
 __base_class_type_info::search2(__dynamic_cast_info* info, const void* dynamic_ptr,
                                 int path_below) const
@@ -347,7 +385,7 @@
     if (__offset_flags & __virtual_mask)
     {
         char* vtable = *(char**)dynamic_ptr;
-        offset_to_base = (ptrdiff_t)vtable[offset_to_base];
+        offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
     }
     return __base_type->search2(info, (char*)dynamic_ptr + offset_to_base,
                                 (__offset_flags & __public_mask) ? path_below :
@@ -378,7 +416,7 @@
     if (__offset_flags & __virtual_mask)
     {
         char* vtable = *(char**)obj;
-        offset_to_base = (ptrdiff_t)vtable[offset_to_base];
+        offset_to_base = *(ptrdiff_t*)(vtable + offset_to_base);
     }
     __base_type->display((char*)obj + offset_to_base);
 }
@@ -426,7 +464,7 @@
 //        ambiguity, or
 //    3.  nullptr
 // Knowns:
-//     (dynamic_ptr, dynamic_type) can be derived from static_ptr.
+//     (dynamic_ptr, dynamic_type) can be extracted from static_ptr.
 //     dynamic_ptr is a pointer to the complete run time object.
 //     dynamic_type is the type of the complete run time object.
 //     The type hierarchy is a DAG rooted at (dynamic_ptr, dynamic_type) and
@@ -448,6 +486,27 @@
 //           (dynamic_ptr, dynamic_type) to (static_ptr, static_type),
 //           else returns nullptr.
 //        This check is purely an optimization and does not impact correctness.
+// Algorithm:
+//    Extract (dynamic_ptr, dynamic_type) from static_ptr.
+//    If dynamic_type == dst_type
+//       If there is a public path from (dynamic_ptr, dynamic_type) to
+//          (static_ptr, static_type), return dynamic_ptr else return nullptr.
+//    Else dynamic_type != dst_type
+//       If there is a single dst_type derived (below) (static_ptr, static_type)
+//           If the path from that unique dst_type to (static_ptr, static_type)
+//              is public, return a pointer to that dst_type else return nullptr.
+//           Else if there are no dst_type's which don't point to (static_ptr, static_type)
+//              and if there is a pubic path from (dynamic_ptr, dynamic_type) to
+//              (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
+//              to the single dst_type, then return a pointer to that dst_type,
+//           Else return nullptr.
+//       Else if there are no dst_type derived (below) (static_ptr, static_type)
+//           And if there is a single dst_type base of (above)
+//               (dynamic_ptr, dynamic_type), and if that single dst_type has a
+//               public path to it.  And if there is a public path
+//               from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
+//               then return a pointer to that single dst_type, else return nullptr.
+//       Else return nullptr.
 extern "C"
 void*
 __dynamic_cast(const void* static_ptr,
@@ -487,7 +546,13 @@
                 dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
             break;
         case 1:
-            if (info.path_dst_ptr_to_static_ptr == public_path)
+            if (info.path_dst_ptr_to_static_ptr == public_path ||
+                   (
+                       info.number_to_dst_ptr == 0 &&
+                       info.path_dynamic_ptr_to_static_ptr == public_path &&
+                       info.path_dynamic_ptr_to_dst_ptr == public_path
+                   )
+               )
                 dst_ptr = info.dst_ptr_leading_to_static_ptr;
             break;
         }

Added: libcxxabi/trunk/test/dynamic_cast3.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/dynamic_cast3.cpp?rev=148038&view=auto
==============================================================================
--- libcxxabi/trunk/test/dynamic_cast3.cpp (added)
+++ libcxxabi/trunk/test/dynamic_cast3.cpp Thu Jan 12 13:48:14 2012
@@ -0,0 +1,2453 @@
+//===------------------------- dynamic_cast3.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 <iostream>
+#include <cassert>
+
+/*
+
+A1   A2   A3
+
+*/
+
+namespace t1
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA3()) == 0);
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == 0);
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t1
+
+/*
+
+A1   A2
+|
+A3
+
+*/
+
+namespace t2
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA3()) == 0);
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t2
+
+namespace t3
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA3()) == 0);
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t3
+
+namespace t4
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA3()) == 0);
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t4
+
+namespace t5
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA3()) == 0);
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t5
+
+/*
+
+A1   A2
+ \  /
+  A3
+
+*/
+
+namespace t6
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t6
+
+namespace t7
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t7
+
+namespace t8
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t8
+
+namespace t9
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t9
+
+namespace t10
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t10
+
+namespace t11
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t11
+
+namespace t12
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t12
+
+namespace t13
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t13
+
+namespace t14
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t14
+
+namespace t15
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      private virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == 0);
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t15
+
+/*
+
+A1
+|
+A2
+|
+A3
+
+*/
+
+namespace t16
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t16
+
+namespace t17
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t17
+
+namespace t18
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t18
+
+namespace t19
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t19
+
+namespace t20
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t20
+
+namespace t21
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t21
+
+namespace t22
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t22
+
+namespace t23
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    t23::A1* getA1() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t23
+
+namespace t24
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    t24::A1* getA1() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t24
+
+namespace t25
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    t25::A1* getA1() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t25
+
+/*
+
+A1 A1
+|  |
+A2 |
+ \ |  
+  A3
+
+*/
+
+namespace t26
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t26
+
+namespace t27
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t27
+
+namespace t28
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t28
+
+namespace t29
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t29
+
+namespace t30
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t30
+
+namespace t31
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t31
+
+namespace t32
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t32
+
+namespace t33
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA12() {return A2::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA12()) == a3.getA12());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA12()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t33
+
+/*
+
+A1
+| \
+A2 \
+ \ |  
+  A3
+
+*/
+
+namespace t34
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t34
+
+namespace t35
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t35
+
+namespace t36
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t36
+
+namespace t37
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t37
+
+namespace t38
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : public virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a2.getA2()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA2()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t38
+
+namespace t39
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : public virtual A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+    assert(dynamic_cast<A1*>(a3.getA3()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t39
+
+namespace t40
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      public A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+    assert(dynamic_cast<A2*>(a3.getA3()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == a3.getA3());
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t40
+
+namespace t41
+{
+
+struct A1
+{
+    char _[43981];
+    virtual ~A1() {std::cout << this << "  ~A1()\n";}
+
+    A1* getA1() {return this;}
+};
+
+struct A2
+    : private virtual A1
+{
+    char _[34981];
+    virtual ~A2() {std::cout << this << "  ~A2()\n";}
+
+    A1* getA1() {return this;}
+    A2* getA2() {return this;}
+};
+
+struct A3
+    : private virtual A1,
+      private A2
+{
+    char _[93481];
+    virtual ~A3() {std::cout << this << "  ~A3()\n";}
+
+    A1* getA1() {return A1::getA1();}
+    A2* getA2() {return this;}
+    A3* getA3() {return this;}
+};
+
+void test()
+{
+    A1 a1;
+    A2 a2;
+    A3 a3;
+    assert(dynamic_cast<A1*>(a1.getA1()) == a1.getA1());
+    assert(dynamic_cast<A1*>(a2.getA1()) == a2.getA1());
+    assert(dynamic_cast<A1*>(a3.getA1()) == a3.getA1());
+
+    assert(dynamic_cast<A2*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a2.getA2()) == a2.getA2());
+    assert(dynamic_cast<A2*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A2*>(a3.getA2()) == a3.getA2());
+
+    assert(dynamic_cast<A3*>(a1.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a2.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA1()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA2()) == 0);
+    assert(dynamic_cast<A3*>(a3.getA3()) == a3.getA3());
+}
+
+}  // t41
+
+int main()
+{
+    t1::test();
+    t2::test();
+    t3::test();
+    t4::test();
+    t5::test();
+    t6::test();
+    t7::test();
+    t8::test();
+    t9::test();
+    t10::test();
+    t11::test();
+    t12::test();
+    t13::test();
+    t14::test();
+    t15::test();
+    t16::test();
+    t17::test();
+    t18::test();
+    t19::test();
+    t20::test();
+    t21::test();
+    t22::test();
+    t23::test();
+    t24::test();
+    t25::test();
+    t26::test();
+    t27::test();
+    t28::test();
+    t29::test();
+    t30::test();
+    t31::test();
+    t32::test();
+    t33::test();
+    t34::test();
+    t35::test();
+    t36::test();
+    t37::test();
+    t38::test();
+    t39::test();
+    t40::test();
+    t41::test();
+}





More information about the cfe-commits mailing list