This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PR c++/20280] hoist indirect_ref out of addressable cond_exprs


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}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]