This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++, ARM]: fix EH catching corner case


This patch fixes a corner case of the ARM C++ ABI. The generic C++ ABI also gets this wrong, because I failed to notice the subtlety here.

The issue is that 15.3/3 3rd bullet says

"the handler is of type cv1 T* cv2 and E is a pointer type that can be converted to the type of the handler by either or both of:

a standard pointer conversion (4.10) not involving conversions to pointers to private or protected or ambiguous classes"

Notice that the handlers of type "cv1 T*cv2&" are not allowed such freedom to find a base class. The ABI error is that we treat handlers of reference type exactly the same as the corresponding hander of non-reference type. Elsewhere in the exception handling this makes no difference (for instance bullet 1 explicitly says 'cv T or cv T&'). As an example, given:

struct A {};
struct B : A {};

  B b;
  throw &b;

we can catch this with 'catch (B *&b)' or 'catch (A *a)', but not 'catch (A *&a)'.

There's no representation in the runtime for a typeinfo of reference type, because everywhere else referenceness is stripped at compile time (expressions do not have reference type). Rather than invent some new typeinfo object, I chose to represent catch clauses of reference type, where the referenceness is significant in matching, by setting bit 0 of the pointer to the typeinfo object describing the catch type. We know this is ok, because such objects are naturally aligned, so the bottom 2 bits will otherwise be zero. The precise details of this are configurable via a target hook, and I provide one that does this bit0 representation.

In order to not effect the generic C++ ABI, the new code paths I introduce are gated on the new target hook being non-NULL. It defaults to NULL and the ARM backend sets it to the new hook function.

In terms of runtime implementation, ARM EABI provides a TARGET2 relocation to describe these typeinfo pointers. The reason being it allows their precise semantics to be deferred to the linker. For bare-metal they turn into absolute relocations. For linux they turn into GOT-REL relocations. Because we've now have a possible non-zero addend, the linux-specific unwinder masks off the bottom 2 bits of the TARGET2 locations, does the indexing and then puts the bottom 2 bits back, thereby propagating referenceness. This is ok, as we're in the personality-specific handling, and although the same TARGET2 decoder is used for the generic unwinder, it'll merely propagate zeroes, because the GOT-relative offset must remain a multiple of 4.

I have not changed the unwinder version number. It's not possible to mix versions of the personality routines in a single executable, so we'd have a problem linking old object files if we changed. On the other hand, if we don't change, new object files that use this new feature linked with the older personality routine will fail at run time. My suspicion is the only code out there that uses this new feature is in some conformance testsuites. So in practice I think the least pain is by keeping the personality version unchanged.

Note that the ARM EABI's C++ unwinder table format does not allow the referenceness of an exception specification to be preserved. ARM have acknowledged a defect in this regard. Because we emit GNU-specific unwinder tables for ARM, we can get this right and mark exception specifications correctly too.

If the generic C++ ABI ever gets amended, we can enable the same change there too. FYI I turned this on for an i686-linux target, and it works fine.

Tested on arm-eabi and arm-linux-gnueabi.

Are the bits outside of the C++ frontend & runtime ok?

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery

2009-08-05  Nathan Sidwell  <nathan@codesourcery.com>

	gcc/
	* targhooks.c (hook_cxx_ttype_ref_in_bit0): New.
	* targhooks.h (hook_cxx_ttype_ref_in_bit0): Declare.
	* target.h (ttype_ref_encode): New field for c++.
	* target-def.h (TARGET_CXX_TTYPE_REF_ENCODE): New.
	(TARGET_CXX): Add it.
	* except.c (output_ttype): If the expression is POINTER_PLUS_EXPR
	look at the first operand for the exception type object.
	* config/arm/arm.c (TARGET_CXX_TTYPE_REF_ENCODE): Override.
	* config/arm/unwind-arm.c (__gnu_unwind_pr_common): Add comment
	about references.
	* config/arm/unwind-arm.h (_Unwind_decode_target2): Propagate the
	bottom 2 bits.

	libstdc++-v3/
	* libsupc++/eh_arm.cc (__cxa_type_match): Use is_reference
	parameter.
	* libsupc++/eh_personality.cc (get_ttype_entry): Add is_ref
	parameter and set it appropriately.
	(get_adjusted_ptr): Add is_ref parameter and use it.
	(check_exception_spec): Pass referenceness to get_adjusted_ptr.
	(PERSONALITY_FUNCTION): Process referenceness.

	gcc/cp/
	* rtti.c (get_tinfo_decl): Assert not reference type.
	* except.c (build_eh_type_type): Use ttype_ref_encode if the type
	is a reference.
	(expand_start_catch_block): Preserve referenceness on pointers if
	ttype_ref_encode is non-NULL.
	(finish_eh_spec_block): Likewise.
	(can_convert_eh): Implement exactly the same algorithm as the
	runtime matcher.
	* semantics.c (finish_handler_parms): Look through reference types
	before marking the exception object type.

	gcc/testsuite/
	* g++.dg/eh/ref1.C: New.
	* g++.dg/eh/ref2.C: New.
	
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 150455)
+++ gcc/targhooks.c	(working copy)
@@ -67,7 +67,6 @@ along with GCC; see the file COPYING3.  
 #include "optabs.h"
 #include "recog.h"
 
-
 bool
 default_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
 			      rtx addr ATTRIBUTE_UNUSED,
@@ -484,6 +483,14 @@ hook_invalid_arg_for_unprototyped_fn (
   return NULL;
 }
 
+tree
+hook_cxx_ttype_ref_in_bit0 (tree exp)
+{
+  exp = fold_build2_loc (EXPR_LOCATION (exp), POINTER_PLUS_EXPR,
+			 TREE_TYPE (exp), exp, size_one_node);
+  return exp;
+}
+
 /* Initialize the stack protection decls.  */
 
 /* Stack protection related decls living in libgcc.  */
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 150455)
+++ gcc/targhooks.h	(working copy)
@@ -56,6 +56,7 @@ extern enum machine_mode default_mode_fo
 
 extern tree default_cxx_guard_type (void);
 extern tree default_cxx_get_cookie_size (tree);
+extern tree hook_cxx_ttype_ref_in_bit0 (tree);
 
 extern bool hook_pass_by_reference_must_pass_in_stack
   (CUMULATIVE_ARGS *, enum machine_mode mode, const_tree, bool);
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 150455)
+++ gcc/target.h	(working copy)
@@ -1024,6 +1024,11 @@ struct gcc_target
        class  (eg, tweak visibility or perform any other required
        target modifications).  */
     void (*adjust_class_at_definition) (tree type);
+    /* Encode a reference type info, used for catching pointer
+       references.  The provided expression will be the address of the
+       type info object of the type to which a reference is being
+       caught.  */
+    tree (* ttype_ref_encode) (tree);
   } cxx;
 
   /* Functions and data for emulated TLS support.  */
Index: gcc/testsuite/g++.dg/eh/ref2.C
===================================================================
--- gcc/testsuite/g++.dg/eh/ref2.C	(revision 0)
+++ gcc/testsuite/g++.dg/eh/ref2.C	(revision 0)
@@ -0,0 +1,70 @@
+// { dg-do run { xfail { ! arm-*-*eabi } } }
+
+// catching a pointer to class by reference prohibits derived->base
+// transformation.   The generic C++ ABI gets this wrong.  ARM EABI
+// gets this right, except for exception specifications where a bug is
+// acknowledged. 
+
+#include <stdio.h>
+#include <exception>
+#include <stdlib.h>
+
+struct A {};
+
+struct B : A {};
+
+B b;
+
+void One () throw (A *&)
+{
+  throw &b;
+}
+
+void Two () throw (A *&, B *&)
+{
+  throw &b;
+}
+
+void Three () throw (A *)
+{
+  throw &b;
+}
+
+int Foo (void (*fn)())
+{
+  try
+    {
+      fn ();
+    }
+  catch (B *b)
+    {
+      printf ("pass, caught B*%p\n", b);
+    }
+  catch (...)
+    {
+      printf ("fail, caught ...");
+      return 1;
+    }
+  return 0;
+}
+
+void handler ()
+{
+  printf ("pass, got unexpected exception\n");
+  exit (0);
+}
+
+int main ()
+{
+  if (Foo (&Three))
+    return 1;
+
+  if (Foo (&Two))
+    return 2;
+
+  std::set_unexpected (handler);
+  if (Foo (&One))
+    return 3;
+  printf ("fail, did not get unexpected exception\n");
+  return 4;
+}
Index: gcc/testsuite/g++.dg/eh/ref1.C
===================================================================
--- gcc/testsuite/g++.dg/eh/ref1.C	(revision 0)
+++ gcc/testsuite/g++.dg/eh/ref1.C	(revision 0)
@@ -0,0 +1,61 @@
+// { dg-do run { xfail { ! arm-*-*eabi } } }
+
+// catching a pointer to class by reference prohibits derived->base
+// transformation.   The generic C++ ABI gets this wrong.  ARM EABI
+// gets this right, except for exception specifications where a bug is
+// acknowledged. 
+
+#include <stdio.h>
+
+struct A {};
+
+struct B : A {};
+
+int Foo ()
+{
+  B b;
+  
+  try
+    {
+      throw &b;
+    }
+  catch (A *&a)
+    {
+      printf ("fail, caught A*&%p\n", a);
+      return 1;
+    }
+  catch (B *&b)
+    {
+      printf ("pass, caught B*&%p\n", b);
+    }
+  catch (...)
+    {
+      printf ("fail, caught ...");
+      return 2;
+    }
+  try
+    {
+      throw &b;
+    }
+  catch (A *a) // { dg-warning "by earlier handler" }
+    {
+      printf ("pass, caught A*%p\n", a);
+    }
+  catch (B *b) // { dg-warning "will be caught" }
+    {
+      printf ("fail, caught B*%p\n", b);
+      return 3;
+    }
+  catch (...)
+    {
+      printf ("fail, caught ...");
+      return 4;
+    }
+  return 0;
+}
+
+
+int main ()
+{
+  return Foo ();
+}
Index: gcc/cp/rtti.c
===================================================================
--- gcc/cp/rtti.c	(revision 150455)
+++ gcc/cp/rtti.c	(working copy)
@@ -392,6 +392,7 @@ get_tinfo_decl (tree type)
 	return d;
     }
 
+  gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
   name = mangle_typeinfo_for_type (type);
 
   d = IDENTIFIER_GLOBAL_VALUE (name);
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	(revision 150455)
+++ gcc/cp/except.c	(working copy)
@@ -146,14 +146,26 @@ eh_type_info (tree type)
 static tree
 build_eh_type_type (tree type)
 {
-  tree exp = eh_type_info (type);
+  bool is_ref = TREE_CODE (type) == REFERENCE_TYPE;
+  tree exp;
+  
+  if (is_ref)
+    type = TREE_TYPE (type);
+  
+  exp = eh_type_info (type);
 
   if (!exp)
     return NULL;
 
   mark_used (exp);
 
-  return convert (ptr_type_node, build_address (exp));
+  exp = build_address (exp);
+  
+  if (is_ref)
+    exp = targetm.cxx.ttype_ref_encode (exp);
+
+  exp = convert (ptr_type_node, exp);
+  return exp;
 }
 
 tree
@@ -497,6 +509,16 @@ expand_start_catch_block (tree decl)
       initialize_handler_parm (decl, exp);
     }
 
+  /* Preserve the reference type on the exception, as this affects
+     derived-to-base conversions in catch matching.  Only do this when
+     the ABI supports it, as originally this case was (incorrectly)
+     treated just as catching a pointer-to-class by value. */
+  if (targetm.cxx.ttype_ref_encode
+      && decl && TREE_CODE (type) == POINTER_TYPE
+      && CLASS_TYPE_P (TREE_TYPE (type))
+      && TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
+    type = build_reference_type (type);
+
   return type;
 }
 
@@ -540,10 +562,20 @@ finish_eh_spec_block (tree raw_raises, t
        raw_raises && TREE_VALUE (raw_raises);
        raw_raises = TREE_CHAIN (raw_raises))
     {
-      tree type = prepare_eh_type (TREE_VALUE (raw_raises));
+      tree orig_type = TREE_VALUE (raw_raises);
+      tree type = prepare_eh_type (orig_type);
       tree tinfo = eh_type_info (type);
 
       mark_used (tinfo);
+      /* Preserve the reference type on the exception, as this affects
+	 derived-to-base conversions in catch matching.  Only do this when
+	 the ABI supports it, as originally this case was (incorrectly)
+	 treated just as catching a pointer-to-class by value. */
+      if (targetm.cxx.ttype_ref_encode
+	  && TREE_CODE (orig_type) == REFERENCE_TYPE
+	  && TREE_CODE (type) == POINTER_TYPE
+	  && CLASS_TYPE_P (TREE_TYPE (type)))
+	type = build_reference_type (type);
       raises = tree_cons (NULL_TREE, type, raises);
     }
 
@@ -959,24 +991,40 @@ nothrow_libfn_p (const_tree fn)
 static int
 can_convert_eh (tree to, tree from)
 {
-  to = non_reference (to);
-  from = non_reference (from);
+  bool to_ref = TREE_CODE (to) == REFERENCE_TYPE;
+  int depth = to_ref;
+  bool outer_const = true;
 
-  if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
+  if (to_ref)
+    to = TREE_TYPE (to);
+  from = non_reference (from);
+  
+  while (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
     {
+      unsigned to_quals, from_quals;
+      
+      depth++;
+      
       to = TREE_TYPE (to);
       from = TREE_TYPE (from);
+      to_quals = TYPE_QUALS (to);
+      from_quals = TYPE_QUALS (from);
 
-      if (! at_least_as_qualified_p (to, from))
+      if ((from_quals & ~to_quals)
+	  || (!outer_const && to_quals & ~from_quals))
 	return 0;
-
-      if (TREE_CODE (to) == VOID_TYPE)
-	return 1;
-
-      /* Else fall through.  */
+	
+      if (!(to_quals & TYPE_QUAL_CONST))
+	outer_const = false;
     }
 
-  if (CLASS_TYPE_P (to) && CLASS_TYPE_P (from)
+  if (same_type_ignoring_top_level_qualifiers_p (from, to))
+    return 1;
+
+  if (depth == to_ref + 1 && TREE_CODE (to) == VOID_TYPE)
+    return 1;
+  
+  if (depth < 2 && CLASS_TYPE_P (to) && CLASS_TYPE_P (from)
       && PUBLICLY_UNIQUELY_DERIVED_P (to, from))
     return 1;
 
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 150455)
+++ gcc/cp/semantics.c	(working copy)
@@ -1119,7 +1119,11 @@ finish_handler_parms (tree decl, tree ha
     type = expand_start_catch_block (decl);
   HANDLER_TYPE (handler) = type;
   if (!processing_template_decl && type)
-    mark_used (eh_type_info (type));
+    {
+      if (TREE_CODE (type) == REFERENCE_TYPE)
+	type = TREE_TYPE (type);
+      mark_used (eh_type_info (type));
+    }
 }
 
 /* Finish a handler, which may be given by HANDLER.  The BLOCKs are
Index: gcc/except.c
===================================================================
--- gcc/except.c	(revision 150455)
+++ gcc/except.c	(working copy)
@@ -4166,6 +4166,12 @@ output_ttype (tree type, int tt_format, 
 	 paths below go through assemble_integer, which would take
 	 care of this for us.  */
       STRIP_NOPS (type);
+      if (TREE_CODE (type) == POINTER_PLUS_EXPR)
+	{
+	  gcc_assert (TREE_CODE (TREE_OPERAND (type, 1)) == INTEGER_CST);
+	  type = TREE_OPERAND (type, 0);
+	  STRIP_NOPS (type);
+	}
       if (TREE_CODE (type) == ADDR_EXPR)
 	{
 	  type = TREE_OPERAND (type, 0);
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 150455)
+++ gcc/target-def.h	(working copy)
@@ -731,6 +731,11 @@
 #define TARGET_CXX_ADJUST_CLASS_AT_DEFINITION hook_void_tree
 #endif
 
+
+#ifndef TARGET_CXX_TTYPE_REF_ENCODE
+#define TARGET_CXX_TTYPE_REF_ENCODE NULL
+#endif
+
 #define TARGET_CXX				\
   {						\
     TARGET_CXX_GUARD_TYPE,			\
@@ -745,7 +750,8 @@
     TARGET_CXX_LIBRARY_RTTI_COMDAT,	        \
     TARGET_CXX_USE_AEABI_ATEXIT,		\
     TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT,	\
-    TARGET_CXX_ADJUST_CLASS_AT_DEFINITION	\
+    TARGET_CXX_ADJUST_CLASS_AT_DEFINITION,	\
+    TARGET_CXX_TTYPE_REF_ENCODE			\
   }
 
 /* EMUTLS specific */
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 150455)
+++ gcc/config/arm/arm.c	(working copy)
@@ -400,6 +400,9 @@ static const struct attribute_spec arm_a
 #undef TARGET_ASM_TTYPE
 #define TARGET_ASM_TTYPE arm_output_ttype
 
+#undef TARGET_CXX_TTYPE_REF_ENCODE
+#define TARGET_CXX_TTYPE_REF_ENCODE hook_cxx_ttype_ref_in_bit0
+
 #undef TARGET_ARM_EABI_UNWINDER
 #define TARGET_ARM_EABI_UNWINDER true
 #endif /* TARGET_UNWIND_INFO */
Index: gcc/config/arm/unwind-arm.c
===================================================================
--- gcc/config/arm/unwind-arm.c	(revision 150455)
+++ gcc/config/arm/unwind-arm.c	(working copy)
@@ -1168,6 +1168,9 @@ __gnu_unwind_pr_common (_Unwind_State st
 			{
 			  matched = (void *)(ucbp + 1);
 			  rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]);
+			  /* There is no way to encode an exception
+			     specification for 'class X * &', so
+			     always pass false for is_reference.  */
 			  if (__cxa_type_match (ucbp, (type_info *) rtti, 0,
 						&matched))
 			    break;
Index: gcc/config/arm/unwind-arm.h
===================================================================
--- gcc/config/arm/unwind-arm.h	(revision 150455)
+++ gcc/config/arm/unwind-arm.h	(working copy)
@@ -229,9 +229,10 @@ extern "C" {
 	return 0;
 
 #if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__)
-      /* Pc-relative indirect.  */
+      /* Pc-relative indirect.  Propagate the bottom 2 bits, which can
+	 contain referenceness information in gnu unwinding tables.  */
       tmp += ptr;
-      tmp = *(_Unwind_Word *) tmp;
+      tmp = *(_Unwind_Word *) (tmp & ~(_Unwind_Word)3) | (tmp & 3);
 #elif defined(__symbian__) || defined(__uClinux__)
       /* Absolute pointer.  Nothing more to do.  */
 #else
Index: libstdc++-v3/libsupc++/eh_arm.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_arm.cc	(revision 150455)
+++ libstdc++-v3/libsupc++/eh_arm.cc	(working copy)
@@ -38,7 +38,7 @@ using namespace __cxxabiv1;
 extern "C" __cxa_type_match_result
 __cxa_type_match(_Unwind_Exception* ue_header,
 		 const std::type_info* catch_type,
-		 bool is_reference __attribute__((__unused__)),
+		 bool is_reference,
 		 void** thrown_ptr_p)
 {
   bool forced_unwind = __is_gxx_forced_unwind_class(ue_header->exception_class);
@@ -68,11 +68,11 @@ __cxa_type_match(_Unwind_Exception* ue_h
   if (throw_type->__is_pointer_p())
     thrown_ptr = *(void**) thrown_ptr;
 
-  if (catch_type->__do_catch(throw_type, &thrown_ptr, 1))
+  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1 + is_reference * 2))
     {
       *thrown_ptr_p = thrown_ptr;
 
-      if (typeid(*catch_type) == typeid (typeid(void*)))
+      if (typeid (*catch_type) == typeid (typeid(void*)))
 	{
 	  const __pointer_type_info *catch_pointer_type =
 	    static_cast<const __pointer_type_info *> (catch_type);
Index: libstdc++-v3/libsupc++/eh_personality.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_personality.cc	(revision 150455)
+++ libstdc++-v3/libsupc++/eh_personality.cc	(working copy)
@@ -89,20 +89,22 @@ parse_lsda_header (_Unwind_Context *cont
 // Return an element from a type table.
 
 static const std::type_info*
-get_ttype_entry(lsda_header_info* info, _uleb128_t i)
+get_ttype_entry(lsda_header_info* info, _uleb128_t i, bool &is_ref)
 {
   _Unwind_Ptr ptr;
 
   ptr = (_Unwind_Ptr) (info->TType - (i * 4));
   ptr = _Unwind_decode_target2(ptr);
   
-  return reinterpret_cast<const std::type_info *>(ptr);
+  is_ref = ptr & 1;
+  
+  return reinterpret_cast<const std::type_info *>(ptr & ~1);
 }
 
 // The ABI provides a routine for matching exception object types.
 typedef _Unwind_Control_Block _throw_typet;
-#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \
-  (__cxa_type_match (throw_type, catch_type, false, thrown_ptr_p) \
+#define get_adjusted_ptr(catch_type, throw_type, is_ref, thrown_ptr_p) \
+  (__cxa_type_match (throw_type, catch_type, is_ref, thrown_ptr_p) \
    != ctm_failed)
 
 // Return true if THROW_TYPE matches one if the filter types.
@@ -118,6 +120,7 @@ check_exception_spec(lsda_header_info* i
     {
       const std::type_info* catch_type;
       _uleb128_t tmp;
+      bool is_ref;
 
       tmp = *e;
       
@@ -129,13 +132,14 @@ check_exception_spec(lsda_header_info* i
       tmp = _Unwind_decode_target2((_Unwind_Word) e);
 
       // Match a ttype entry.
-      catch_type = reinterpret_cast<const std::type_info*>(tmp);
+      is_ref = tmp & 1;
+      catch_type = reinterpret_cast<const std::type_info*>(tmp & ~1);
 
       // ??? There is currently no way to ask the RTTI code about the
       // relationship between two types without reference to a specific
       // object.  There should be; then we wouldn't need to mess with
       // thrown_ptr here.
-      if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))
+      if (get_adjusted_ptr(catch_type, throw_type, is_ref, &thrown_ptr))
 	return true;
 
       // Advance to the next entry.
@@ -207,7 +211,7 @@ typedef const std::type_info _throw_type
 // Return an element from a type table.
 
 static const std::type_info *
-get_ttype_entry (lsda_header_info *info, _uleb128_t i)
+get_ttype_entry (lsda_header_info *info, _uleb128_t i, bool &is_ref)
 {
   _Unwind_Ptr ptr;
 
@@ -215,7 +219,9 @@ get_ttype_entry (lsda_header_info *info,
   read_encoded_value_with_base (info->ttype_encoding, info->ttype_base,
 				info->TType - i, &ptr);
 
-  return reinterpret_cast<const std::type_info *>(ptr);
+  is_ref = ptr & 1;
+  
+  return reinterpret_cast<const std::type_info *>(ptr & ~1);
 }
 
 // Given the thrown type THROW_TYPE, pointer to a variable containing a
@@ -226,6 +232,7 @@ get_ttype_entry (lsda_header_info *info,
 static bool
 get_adjusted_ptr (const std::type_info *catch_type,
 		  const std::type_info *throw_type,
+		  bool is_ref,
 		  void **thrown_ptr_p)
 {
   void *thrown_ptr = *thrown_ptr_p;
@@ -237,7 +244,7 @@ get_adjusted_ptr (const std::type_info *
   if (throw_type->__is_pointer_p ())
     thrown_ptr = *(void **) thrown_ptr;
 
-  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
+  if (catch_type->__do_catch (throw_type, &thrown_ptr, 1 + is_ref * 2))
     {
       *thrown_ptr_p = thrown_ptr;
       return true;
@@ -267,13 +274,15 @@ check_exception_spec(lsda_header_info* i
         return false;
 
       // Match a ttype entry.
-      catch_type = get_ttype_entry (info, tmp);
+      bool is_ref;
+      
+      catch_type = get_ttype_entry (info, tmp, is_ref);
 
       // ??? There is currently no way to ask the RTTI code about the
       // relationship between two types without reference to a specific
       // object.  There should be; then we wouldn't need to mess with
       // thrown_ptr here.
-      if (get_adjusted_ptr (catch_type, throw_type, &thrown_ptr))
+      if (get_adjusted_ptr (catch_type, throw_type, is_ref, &thrown_ptr))
 	return true;
     }
 }
@@ -582,14 +591,16 @@ PERSONALITY_FUNCTION (int version,
 	  else if (ar_filter > 0)
 	    {
 	      // Positive filter values are handlers.
-	      catch_type = get_ttype_entry (&info, ar_filter);
+	      bool is_ref;
+	      
+	      catch_type = get_ttype_entry (&info, ar_filter, is_ref);
 
 	      // Null catch type is a catch-all handler; we can catch foreign
 	      // exceptions with this.  Otherwise we must match types.
 	      if (! catch_type
 		  || (throw_type
 		      && get_adjusted_ptr (catch_type, throw_type,
-					   &thrown_ptr)))
+					   is_ref, &thrown_ptr)))
 		{
 		  saw_handler = true;
 		  break;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]