From f98251686f1e33a6698e9d118d7f1c6a600c0c23 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 27 Nov 2000 10:55:32 +0000 Subject: [PATCH] cp-tree.h (binfo_from_vbase): Return the virtual base's binfo. cp: * cp-tree.h (binfo_from_vbase): Return the virtual base's binfo. * cvt.c (cp_convert_to_pointer): Add force parameter. Allow conversions via virtual base if forced. (convert_to_pointer_force): Adjust call to cp_convert_to_pointer. (ocp_convert): Likewise. * search.c (binfo_from_vbase): Return the virtual base's binfo. * typeck.c (get_delta_difference): Adjust handling of virtual bases. testsuite: * g++.old-deja/g++.other/ptrmem8.C: New test. From-SVN: r37791 --- gcc/cp/ChangeLog | 11 +++ gcc/cp/cp-tree.h | 2 +- gcc/cp/cvt.c | 32 +++++--- gcc/cp/search.c | 9 ++- gcc/cp/typeck.c | 26 ++++--- gcc/testsuite/ChangeLog | 4 + .../g++.old-deja/g++.other/ptrmem8.C | 74 +++++++++++++++++++ 7 files changed, 133 insertions(+), 25 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/ptrmem8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7b36db17751..f2b1adc92ec 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2000-11-27 Nathan Sidwell + + * cp-tree.h (binfo_from_vbase): Return the virtual base's binfo. + * cvt.c (cp_convert_to_pointer): Add force parameter. + Allow conversions via virtual base if forced. + (convert_to_pointer_force): Adjust call to cp_convert_to_pointer. + (ocp_convert): Likewise. + * search.c (binfo_from_vbase): Return the virtual base's binfo. + * typeck.c (get_delta_difference): Adjust handling of virtual + bases. + 2000-11-26 Mark Mitchell * tree.c (struct list_hash): Remove. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ed233a2e92a..ab10f46c2ec 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4265,7 +4265,7 @@ extern tree current_scope PARAMS ((void)); extern int at_function_scope_p PARAMS ((void)); extern tree lookup_conversions PARAMS ((tree)); extern tree binfo_for_vtable PARAMS ((tree)); -extern int binfo_from_vbase PARAMS ((tree)); +extern tree binfo_from_vbase PARAMS ((tree)); extern tree dfs_walk PARAMS ((tree, tree (*)(tree, void *), tree (*) (tree, void *), diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 606f854269e..fe99c8f566e 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -35,7 +35,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "decl.h" -static tree cp_convert_to_pointer PARAMS ((tree, tree)); +static tree cp_convert_to_pointer PARAMS ((tree, tree, int)); static tree convert_to_pointer_force PARAMS ((tree, tree)); static tree build_up_reference PARAMS ((tree, tree, int)); static void warn_ref_binding PARAMS ((tree, tree, tree)); @@ -67,11 +67,14 @@ static void warn_ref_binding PARAMS ((tree, tree, tree)); else if dealing with method pointers, delegate else convert blindly else if converting class, pass off to build_type_conversion - else try C-style pointer conversion */ + else try C-style pointer conversion. If FORCE is true then allow + conversions via virtual bases (these are permitted by reinterpret_cast, + but not static_cast). */ static tree -cp_convert_to_pointer (type, expr) +cp_convert_to_pointer (type, expr, force) tree type, expr; + int force; { register tree intype = TREE_TYPE (expr); register enum tree_code form; @@ -184,6 +187,7 @@ cp_convert_to_pointer (type, expr) tree b1; tree b2; tree binfo; + tree virt_binfo; enum tree_code code; b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type)); @@ -201,11 +205,21 @@ cp_convert_to_pointer (type, expr) if (binfo == error_mark_node) return error_mark_node; - if (binfo_from_vbase (binfo)) + virt_binfo = binfo_from_vbase (binfo); + if (virt_binfo) { - cp_error ("conversion to `%T' from pointer to member of virtual base `%T'", - type, intype); - return error_mark_node; + if (force) + cp_warning ("pointer to member cast via virtual base `%T' of `%T' will only work for objects of dynamic type `%T'", + BINFO_TYPE (virt_binfo), + BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)), + code == MINUS_EXPR ? b2 : b1); + else + { + cp_error ("pointer to member cast via virtual base `%T' of `%T'", + BINFO_TYPE (virt_binfo), + BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo))); + return error_mark_node; + } } if (TREE_CODE (expr) == PTRMEM_CST) @@ -334,7 +348,7 @@ convert_to_pointer_force (type, expr) } } - return cp_convert_to_pointer (type, expr); + return cp_convert_to_pointer (type, expr, 1); } /* We are passing something to a function which requires a reference. @@ -777,7 +791,7 @@ ocp_convert (type, expr, convtype, flags) } if (code == POINTER_TYPE || code == REFERENCE_TYPE || TYPE_PTRMEMFUNC_P (type)) - return fold (cp_convert_to_pointer (type, e)); + return fold (cp_convert_to_pointer (type, e, 0)); if (code == REAL_TYPE || code == COMPLEX_TYPE) { if (IS_AGGR_TYPE (TREE_TYPE (e))) diff --git a/gcc/cp/search.c b/gcc/cp/search.c index a7fdc86888b..ae1d64895ed 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -3362,18 +3362,19 @@ binfo_for_vtable (var) return binfo; } -/* Returns 1 iff BINFO is from a direct or indirect virtual base. */ +/* Returns the binfo of the first direct or indirect virtual base from + which BINFO is derrived, or NULL if binfo is not via virtual. */ -int +tree binfo_from_vbase (binfo) tree binfo; { for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo)) { if (TREE_VIA_VIRTUAL (binfo)) - return 1; + return binfo; } - return 0; + return NULL_TREE; } /* Returns the BINFO (if any) for the virtual baseclass T of the class diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d0ca2bbcb28..39f8b54515e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5912,6 +5912,7 @@ get_delta_difference (from, to, force) { tree delta = integer_zero_node; tree binfo; + tree virt_binfo; if (to == from) return delta; @@ -5937,11 +5938,12 @@ get_delta_difference (from, to, force) binfo = get_binfo (to, from, 1); if (binfo == 0 || binfo == error_mark_node) return delta; - if (binfo_from_vbase (binfo)) - { - binfo = binfo_for_vbase (BINFO_TYPE (binfo), from); - cp_warning ("pointer to member cast to virtual base `%T' will only work if you are very careful", BINFO_TYPE (binfo)); - } + virt_binfo = binfo_from_vbase (binfo); + + if (virt_binfo) + cp_warning ("pointer to member cast via virtual base `%T' of `%T' will only work for objects of dynamic type `%T'", + BINFO_TYPE (virt_binfo), + BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)), from); delta = BINFO_OFFSET (binfo); delta = cp_convert (ptrdiff_type_node, delta); @@ -5950,15 +5952,17 @@ get_delta_difference (from, to, force) delta); } - if (binfo_from_vbase (binfo)) + virt_binfo = binfo_from_vbase (binfo); + if (virt_binfo) { if (force) - { - cp_warning ("pointer to member cast from virtual base `%T' will only wokr if you are very careful", BINFO_TYPE (binfo)); - } + cp_warning ("pointer to member cast via virtual base `%T' of `%T' will only work for objects of dynamic type `%T'", + BINFO_TYPE (virt_binfo), + BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)), to); else - cp_error ("pointer to member conversion from virtual base `%T'", - BINFO_TYPE (binfo)); + cp_error ("pointer to member conversion via virtual base `%T' of `%T'", + BINFO_TYPE (virt_binfo), + BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo))); } return BINFO_OFFSET (binfo); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dc86e3872f3..1aeaf03a9dd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2000-11-27 Nathan Sidwell + + * g++.old-deja/g++.other/ptrmem8.C: New test. + 2000-11-26 Kaveh R. Ghazi * gcc.c-torture/execute/string-opt-7.c: New test. diff --git a/gcc/testsuite/g++.old-deja/g++.other/ptrmem8.C b/gcc/testsuite/g++.old-deja/g++.other/ptrmem8.C new file mode 100644 index 00000000000..f99371a39a7 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/ptrmem8.C @@ -0,0 +1,74 @@ +// Copyright (C) 2000 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 22 Nov 2000 + +// bug 827. We died issuing warnings about dangerous pointer to member +// conversions. + +struct bar +{ + int barm; + static void a(); +}; +struct filler1 {int fm;}; +struct filler2 {int fm;}; +struct filler3 {int fm;}; +struct filler4 {int fm;}; + +struct baz : filler1, bar, filler2 +{ + int bazm; +}; + +struct foo : filler3, virtual baz, filler4 +{ + static void a(); + void b() {}; + int m; +}; + +typedef void (bar::*barfPtr)(); +typedef void (foo::*foofPtr)(); +typedef int bar::*barmPtr; +typedef int foo::*foomPtr; + +int main () +{ + foofPtr fp = &foo::b; + barfPtr bp = (barfPtr)fp; // WARNING - pointer to member + foofPtr fp2 = (foofPtr)bp; // WARNING - pointer to member + + if (fp2 != fp) + return 1; + + foo fobj; + fobj.filler1::fm = 1; + fobj.filler2::fm = 2; + fobj.filler3::fm = 3; + fobj.filler4::fm = 4; + fobj.bazm = 5; + fobj.barm = 6; + fobj.m = 78; + + foomPtr fmp = &foo::m; + barmPtr bmp = (barmPtr)fmp; // WARNING - pointer to member + foomPtr fmp2 = (foomPtr)bmp; // WARNING - pointer to member + bar *bptr = &fobj; + + if (fmp != fmp2) + return 2; + + if (bptr->*bmp != 78) + return 3; + + bp = reinterpret_cast (fp); + fp2 = reinterpret_cast (bp); + if (fp2 != fp) + return 4; + + bmp = reinterpret_cast (fmp); + fmp2 = reinterpret_cast (bmp); + if (fmp != fmp2) + return 5; + + return 0; +}