This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PR c++/19199] don't turn cond_expr lvalue into min_expr rvalue (continued from PR c++/20280)
On Mar 4, 2005, Mark Mitchell <mark@codesourcery.com> wrote:
> Actually, looking at this more closely, I think that something is
> forgetting to call rationalize_conditional_expr, which is normally
> called from unary_complex_lvalue. When the conditional expression is
> used in the lvalue context, something should be calling that.
> Normally, that happens because something calls build_unary_op
> (ADDR_EXPR, ...) on the COND_EXPR.
> It may be that I changed something to call build_addr (instead of
> build_unary_op) in a case where that's not safe. Can you confirm or
> deny that hypothesis?
I'm not sure you're still talking about PR 20280, or about PR 19199,
that is marked as a blocker because it appears to be the same problem,
but AFAICT really isn't.
Here's a patch that fixes PR c++/19199, by avoiding the transformation
from:
<cond <lt <nop(int) <parm a> > <nop(int) <parm b> > >
<parm a> <parm b> >
into:
<nop(enum) <min <nop(int) <parm a> > <nop(int) <parm b> > >
since the latter is clearly not an lvalue, and
rationalize_conditional_expr doesn't manage to turn it back into one
(I don't think it should). I realize we might miss some optimization
opportunities because of this change in C, because the optimization
would be valid there, but I suppose we could arrange for cond_expr
operands in C to be forced into rvalues.
Still testing on x86_64-linux-gnu. Ok to install if it passes?
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR c++/19199
* fold-const.c (non_lvalue): Split tests into...
(maybe_lvalue_p): New function.
(fold_ternary): Use it to avoid turning a COND_EXPR lvalue into
an MIN_EXPR rvalue.
Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.523
diff -u -p -r1.523 fold-const.c
--- gcc/fold-const.c 4 Mar 2005 06:24:09 -0000 1.523
+++ gcc/fold-const.c 4 Mar 2005 19:04:26 -0000
@@ -2004,16 +2004,12 @@ fold_convert (tree type, tree arg)
}
}
-/* Return an expr equal to X but certainly not valid as an lvalue. */
+/* Return false if expr can be assumed to not be an lvalue, true
+ otherwise. */
-tree
-non_lvalue (tree x)
+static bool
+maybe_lvalue_p (tree x)
{
- /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
- us. */
- if (in_gimple_form)
- return x;
-
/* We only need to wrap lvalue tree codes. */
switch (TREE_CODE (x))
{
@@ -2053,8 +2049,24 @@ non_lvalue (tree x)
/* Assume the worst for front-end tree codes. */
if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
break;
- return x;
+ return false;
}
+
+ return true;
+}
+
+/* Return an expr equal to X but certainly not valid as an lvalue. */
+
+tree
+non_lvalue (tree x)
+{
+ /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
+ us. */
+ if (in_gimple_form)
+ return x;
+
+ if (! maybe_lvalue_p (x))
+ return x;
return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
}
@@ -7095,10 +7107,17 @@ fold_ternary (tree expr)
of B and C. Signed zeros prevent all of these transformations,
for reasons given above each one.
+ We don't want to use operand_equal_for_comparison_p here,
+ because it might turn an lvalue COND_EXPR into an rvalue one,
+ see PR c++/19199.
+
Also try swapping the arguments and inverting the conditional. */
if (COMPARISON_CLASS_P (arg0)
- && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
- arg1, TREE_OPERAND (arg0, 1))
+ && ((maybe_lvalue_p (arg1)
+ && maybe_lvalue_p (TREE_OPERAND (t, 2)))
+ ? operand_equal_p (TREE_OPERAND (arg0, 0), arg1, OEP_ONLY_CONST)
+ : operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
+ arg1, TREE_OPERAND (arg0, 1)))
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
{
tem = fold_cond_expr_with_comparison (type, arg0,
@@ -7109,9 +7128,13 @@ fold_ternary (tree expr)
}
if (COMPARISON_CLASS_P (arg0)
- && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
- TREE_OPERAND (t, 2),
- TREE_OPERAND (arg0, 1))
+ && ((maybe_lvalue_p (arg1)
+ && maybe_lvalue_p (TREE_OPERAND (t, 2)))
+ ? operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (t, 2), OEP_ONLY_CONST)
+ : operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (t, 2),
+ TREE_OPERAND (arg0, 1)))
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
{
tem = invert_truthvalue (arg0);
Index: gcc/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR c++/19199
* g++.dg/expr/lval2.C: New.
Index: gcc/testsuite/g++.dg/expr/lval2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/expr/lval2.C
diff -N gcc/testsuite/g++.dg/expr/lval2.C
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/expr/lval2.C 4 Mar 2005 19:04:42 -0000
@@ -0,0 +1,26 @@
+// PR c++/19199
+
+// { dg-do run }
+
+// We used to turn the COND_EXPR lvalue into a MIN_EXPR rvalue, and
+// then return a reference to a temporary in qMin.
+
+#include <assert.h>
+
+enum Foo { A, B };
+
+template<typename T> T &qMin(T &a, T &b)
+{
+ return a < b ? a : b;
+}
+
+int main (int, char **)
+{
+ Foo f = A;
+ Foo g = B;
+ Foo &h = qMin(f, g);
+ assert (&h == &f || &h == &g);
+ const Foo &i = qMin((const Foo&)f, (const Foo&)g);
+ assert (&i == &f || &i == &g);
+ return 0;
+}
--
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}