This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PR c++/20280] hoist indirect_ref out of addressable cond_exprs
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, gcc-bugzilla at gcc dot gnu dot org
- Date: 03 Mar 2005 04:50:38 -0300
- Subject: [PR c++/20280] hoist indirect_ref out of addressable cond_exprs
- Organization: Red Hat Global Engineering Services Compiler Team
When passing an lvalue cond_expr to a function taking a reference that
binds directly to either operand of ?:, we'd fail gimplification when
the type of the expressions was addressable, because, once again,
create_tmp_var would reject addressable types.
The solution I came up with was to hoist the indirect_ref out of the
cond_expr at the time it was created, such that we create a tmp_var
with a reference to the result of the cond_expr, and when we take the
address of the cond_expr to pass its result by reference, it cancels
out with the indirect_ref, so it works beautifully.
I went ahead and verified that I didn't break bit-field lvalues in
conditional expressions (my first attempt did), but I was surprised to
find out that the calls to h() pass. I understand why they do (we
create a temporary and bind to that), but I'm not sure this is correct
behavior. Opinions?
I'm bootstrapping this on x86_64-linux-gnu, along with the patch for
PR c++/20103; it's also passed C++ regression testing. Ok to install
if bootstrap and all-languages regression testing passes?
Index: gcc/cp/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR c++/20280
* call.c (build_conditional_expr): Hoist indirect_ref out of
cond_expr if the result is an addressable lvalue.
Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.531
diff -u -p -r1.531 call.c
--- gcc/cp/call.c 24 Feb 2005 21:55:10 -0000 1.531
+++ gcc/cp/call.c 3 Mar 2005 07:42:24 -0000
@@ -3111,6 +3111,7 @@ build_conditional_expr (tree arg1, tree
tree result = NULL_TREE;
tree result_type = NULL_TREE;
bool lvalue_p = true;
+ bool indirect_p = false;
struct z_candidate *candidates = 0;
struct z_candidate *cand;
void *p;
@@ -3292,7 +3293,15 @@ build_conditional_expr (tree arg1, tree
&& real_lvalue_p (arg3)
&& same_type_p (arg2_type, arg3_type))
{
- result_type = arg2_type;
+ if (TREE_ADDRESSABLE (arg2_type) && TREE_ADDRESSABLE (arg3_type))
+ {
+ indirect_p = true;
+ result_type = build_pointer_type (arg2_type);
+ arg2 = fold_if_not_in_template (build_address (arg2));
+ arg3 = fold_if_not_in_template (build_address (arg3));
+ }
+ else
+ result_type = arg2_type;
goto valid_operands;
}
@@ -3458,6 +3467,14 @@ build_conditional_expr (tree arg1, tree
/* We can't use result_type below, as fold might have returned a
throw_expr. */
+ if (indirect_p)
+ {
+ if (TREE_CODE (TREE_TYPE (result)) == POINTER_TYPE)
+ result = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (result)), result);
+ else
+ gcc_assert (TREE_CODE (result) == THROW_EXPR);
+ }
+
/* Expand both sides into the same slot, hopefully the target of the
?: expression. We used to check for TARGET_EXPRs here, but now we
sometimes wrap them in NOP_EXPRs so the test would fail. */
Index: gcc/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* g++.dg/tree-ssa/pr20103.C: New.
Index: gcc/testsuite/g++.dg/tree-ssa/pr20280.C
===================================================================
RCS file: gcc/testsuite/g++.dg/tree-ssa/pr20280.C
diff -N gcc/testsuite/g++.dg/tree-ssa/pr20280.C
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/tree-ssa/pr20280.C 3 Mar 2005 07:42:38 -0000
@@ -0,0 +1,62 @@
+// PR c++/20280
+
+// { dg-do compile }
+
+// Gimplification of the COND_EXPR used to fail because it had an
+// addressable type, and create_tmp_var rejected that.
+
+struct A
+{
+ ~A();
+};
+
+struct B : A {};
+
+A& foo();
+
+void bar(bool b)
+{
+ (B&) (b ? foo() : foo());
+}
+
+// Make sure bit-fields and addressable types don't cause crashes.
+// These were not in the original bug report.
+
+// Added by Alexandre Oliva <aoliva@redhat.com>
+
+// Copyright 2005 Free Software Foundation
+
+struct X
+{
+ long i : 32, j, k : 32;
+};
+
+void g(long&);
+void h(const long&);
+
+void f(X &x, bool b)
+{
+ (b ? x.i : x.j) = 1;
+ (b ? x.j : x.k) = 2;
+ (b ? x.i : x.k) = 3;
+
+ (void)(b ? x.i : x.j);
+ (void)(b ? x.i : x.k);
+ (void)(b ? x.j : x.k);
+
+ g (b ? x.i : x.j); // { dg-error "cannot bind bitfield" }
+ g (b ? x.i : x.k); // { dg-error "cannot bind bitfield" }
+ g (b ? x.j : x.k); // { dg-error "cannot bind bitfield" }
+
+ // Hmm... I don't think these should be accepted. The conditional
+ // expressions are lvalues for sure, and 8.5.3/5 exempts lvalues
+ // that are bit-fields, but not lvalues that are conditional
+ // expressions involving bit-fields.
+ h (b ? x.i : x.j);
+ h (b ? x.i : x.k);
+ h (b ? x.j : x.k);
+
+ (long &)(b ? x.i : x.j); // { dg-error "address of bit-field" }
+ (long &)(b ? x.i : x.k); // { dg-error "address of bit-field" }
+ (long &)(b ? x.j : x.k); // { dg-error "address of bit-field" }
+}
--
Alexandre Oliva http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org}