diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2005-04-04 17:45:16 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2005-04-04 17:45:16 +0000 |
commit | 38a37714e672206ae98b499861ec23eaff0909e0 (patch) | |
tree | b1c370ce6f0a73b8b6bd72c7bbb2a3dc0e3f62ff | |
parent | 6d6f2d0804ab464f43e5f20563948dc85542a50a (diff) | |
download | gcc-38a37714e672206ae98b499861ec23eaff0909e0.zip gcc-38a37714e672206ae98b499861ec23eaff0909e0.tar.gz gcc-38a37714e672206ae98b499861ec23eaff0909e0.tar.bz2 |
re PR c++/20746 ([4.0 only] Incorrect return value for covariant return function returning null ptr)
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
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/method.c | 23 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/covariant5.C | 52 |
4 files changed, 81 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c50d7d2..f38b03d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 70d6642..9036f64 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 507f14a..ddb7ae2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..03e55583 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/covariant5.C @@ -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; +} |