aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2007-04-13 19:43:18 -0400
committerJason Merrill <jason@gcc.gnu.org>2007-04-13 19:43:18 -0400
commit44ba4c4e1cb90013da81aa1fa89b45122b6a31ab (patch)
treeda8e16c89d428eff3f1285c537a96d013de3bed5 /gcc
parent9a7b07c6c1f2dec0104055d7a0a4a4f2bfc11729 (diff)
downloadgcc-44ba4c4e1cb90013da81aa1fa89b45122b6a31ab.zip
gcc-44ba4c4e1cb90013da81aa1fa89b45122b6a31ab.tar.gz
gcc-44ba4c4e1cb90013da81aa1fa89b45122b6a31ab.tar.bz2
re PR c++/31074 (Reference casting involving multiple inheritance produces bad pointer)
PR c++/31074 * call.c (reference_binding): Add c_cast_p parm. If true, add quals to TO as needed to make it reference-compatible. From-SVN: r123805
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/call.c19
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/inherit/conv3.C31
4 files changed, 55 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 663b3e1..9d0ac8cc 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2007-04-13 Jason Merrill <jason@redhat.com>
+
+ PR c++/31074
+ * call.c (reference_binding): Add c_cast_p parm. If true,
+ add quals to TO as needed to make it reference-compatible.
+
2007-04-11 Jan Hubicka <jh@suse.cz>
* cp/class.c (convert_to_base_statically): Fold produced tree; verify
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 320e51c..0b0bb64 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -173,7 +173,7 @@ static struct z_candidate *add_function_candidate
(struct z_candidate **, tree, tree, tree, tree, tree, int);
static conversion *implicit_conversion (tree, tree, tree, bool, int);
static conversion *standard_conversion (tree, tree, tree, bool, int);
-static conversion *reference_binding (tree, tree, tree, int);
+static conversion *reference_binding (tree, tree, tree, bool, int);
static conversion *build_conv (conversion_kind, tree, conversion *);
static bool is_subseq (conversion *, conversion *);
static tree maybe_handle_ref_bind (conversion **);
@@ -1105,10 +1105,11 @@ direct_reference_binding (tree type, conversion *conv)
purposes of reference binding. For lvalue binding, either pass a
reference type to FROM or an lvalue expression to EXPR. If the
reference will be bound to a temporary, NEED_TEMPORARY_P is set for
- the conversion returned. */
+ the conversion returned. If C_CAST_P is true, this
+ conversion is coming from a C-style cast. */
static conversion *
-reference_binding (tree rto, tree rfrom, tree expr, int flags)
+reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
{
conversion *conv = NULL;
tree to = TREE_TYPE (rto);
@@ -1138,6 +1139,11 @@ reference_binding (tree rto, tree rfrom, tree expr, int flags)
reference compatible. We have do do this after stripping
references from FROM. */
related_p = reference_related_p (to, from);
+ /* If this is a C cast, first convert to an appropriately qualified
+ type, so that we can later do a const_cast to the desired type. */
+ if (related_p && c_cast_p
+ && !at_least_as_qualified_p (to, from))
+ to = build_qualified_type (to, cp_type_quals (from));
compatible_p = reference_compatible_p (to, from);
if (lvalue_p && compatible_p)
@@ -1247,7 +1253,7 @@ reference_binding (tree rto, tree rfrom, tree expr, int flags)
if (related_p && !at_least_as_qualified_p (to, from))
return NULL;
- conv = implicit_conversion (to, from, expr, /*c_cast_p=*/false,
+ conv = implicit_conversion (to, from, expr, c_cast_p,
flags);
if (!conv)
return NULL;
@@ -1277,7 +1283,7 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
return NULL;
if (TREE_CODE (to) == REFERENCE_TYPE)
- conv = reference_binding (to, from, expr, flags);
+ conv = reference_binding (to, from, expr, c_cast_p, flags);
else
conv = standard_conversion (to, from, expr, c_cast_p, flags);
@@ -6618,7 +6624,8 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
- conv = reference_binding (type, TREE_TYPE (expr), expr, LOOKUP_NORMAL);
+ conv = reference_binding (type, TREE_TYPE (expr), expr, /*c_cast_p=*/false,
+ LOOKUP_NORMAL);
if (!conv || conv->bad_p)
{
if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2b0d880..118d9ad 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-04-13 Jason Merrill <jason@redhat.com>
+
+ PR c++/31074
+ * conv3.C: New test.
+
2007-04-13 Mike Stump <mrs@apple.com>
* obj-c++.dg/stubify-1.mm: Only run on powerpc.
diff --git a/gcc/testsuite/g++.dg/inherit/conv3.C b/gcc/testsuite/g++.dg/inherit/conv3.C
new file mode 100644
index 0000000..73d8c20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/inherit/conv3.C
@@ -0,0 +1,31 @@
+// PR 31074
+// Bug: The reference cast wasn't finding the desired static_cast followed by
+// const_cast interpretation.
+
+struct Shape
+{
+ Shape() {}
+ virtual ~Shape() {}
+};
+
+struct Loop
+{
+ Loop() {}
+ virtual ~Loop() {}
+ virtual void func() {}
+};
+
+struct Rect :
+ public Shape,
+ public Loop
+{
+ Rect() {}
+ virtual ~Rect() {}
+};
+
+int main ()
+{
+ const Rect* rect = new Rect();
+ Loop &l = ((Loop&)(*rect));
+ return (&l != (const Loop *)rect);
+}