re PR c++/20746 ([4.0 only] Incorrect return value for covariant return function...
authorNathan Sidwell <nathan@codesourcery.com>
Mon, 4 Apr 2005 17:45:16 +0000 (17:45 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 4 Apr 2005 17:45:16 +0000 (17:45 +0000)
cp:
PR c++/20746
* method.c (use_thunk): Protect covariant pointer return
adjustments from NULL pointers.
testsuite:
PR c++/20746
* g++.dg/abi/covariant5.C: New.

From-SVN: r97557

gcc/cp/ChangeLog
gcc/cp/method.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/covariant5.C [new file with mode: 0644]

index c50d7d2c4cc9d2bcc0f6ebf945eeb7f420d4b835..f38b03dda3040945ace093ec80b2d9772c57c944 100644 (file)
@@ -1,3 +1,9 @@
+2005-04-04  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/20746
+       * method.c (use_thunk): Protect covariant pointer return
+       adjustments from NULL pointers.
+
 2005-04-04  Jan Hubicka  <jh@suse.cz>
 
        * decl2.c (finish_objects): Revert my previous patch.
index 70d664283bbdbf8bd962e2ef9e8135b534099dba..9036f64c80286a6375941c6086039d107c010b04 100644 (file)
@@ -470,10 +470,27 @@ use_thunk (tree thunk_fndecl, bool emit_p)
        finish_expr_stmt (t);
       else
        {
-         t = force_target_expr (TREE_TYPE (t), t);
          if (!this_adjusting)
-           t = thunk_adjust (t, /*this_adjusting=*/0,
-                             fixed_offset, virtual_offset);
+           {
+             tree cond = NULL_TREE;
+
+             if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+               {
+                 /* If the return type is a pointer, we need to
+                    protect against NULL.  We know there will be an
+                    adjustment, because that's why we're emitting a
+                    thunk.  */
+                 t = save_expr (t);
+                 cond = cp_convert (boolean_type_node, t);
+               }
+             
+             t = thunk_adjust (t, /*this_adjusting=*/0,
+                               fixed_offset, virtual_offset);
+             if (cond)
+               t = build3 (COND_EXPR, TREE_TYPE (t), cond, t,
+                           cp_convert (TREE_TYPE (t), integer_zero_node));
+           }
+         t = force_target_expr (TREE_TYPE (t), t);
          finish_return_stmt (t);
        }
 
index 507f14a6fafa277c44d1174ff934ed61b3e0db91..ddb7ae2d5103f0b1fe55a92b1aeaa41b322df02e 100644 (file)
@@ -1,5 +1,8 @@
 2005-04-04  Nathan Sidwell  <nathan@codesourcery.com>
 
+       PR c++/20746
+       * g++.dg/abi/covariant5.C: New.
+
        PR debug/20505
        * g++.dg/debug/const2.C: New.
 
diff --git a/gcc/testsuite/g++.dg/abi/covariant5.C b/gcc/testsuite/g++.dg/abi/covariant5.C
new file mode 100644 (file)
index 0000000..03e5558
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright (C) 2005 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 4 Apr 2005 <nathan@codesourcery.com>
+
+// { dg-do run }
+
+// PR 20746: Covariant return pointer could be null.
+
+// Origin: yanliu@ca.ibm.com
+//         nathan@codesourcery.com
+
+struct A {
+  virtual void One ();
+};
+struct B  { 
+  virtual B *Two ();
+  virtual B &Three ();
+};
+
+struct C : A, B
+{
+  virtual C *Two (); 
+  virtual C &Three (); 
+};
+void A::One () {}
+B *B::Two()    {return this;}
+B &B::Three()    {return *this;}
+C *C::Two ()   {return 0;}
+C &C::Three ()   {return *(C *)0;}
+
+B *Foo (B *b)
+{
+  return b->Two ();
+}
+
+B &Bar (B *b)
+{
+  return b->Three ();
+}
+
+int main ()
+{
+  C c;
+
+  /* We should not adjust a null pointer.  */
+  if (Foo (&c))
+    return 1;
+  /* But we should adjust a (bogus) null reference.  */
+  if (!&Bar (&c))
+    return 2;
+
+  return 0;
+}