PR c++/64372 - CWG 1560, gratuitous lvalue-rvalue conversion in ?:
authorJason Merrill <jason@redhat.com>
Tue, 15 May 2018 21:56:29 +0000 (17:56 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 15 May 2018 21:56:29 +0000 (17:56 -0400)
* call.c (build_conditional_expr_1): Don't force_rvalue when one arm
is a throw-expression.

From-SVN: r260272

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/g++.dg/cpp1y/dr1560.C [new file with mode: 0644]

index 322c5b9..fe80f72 100644 (file)
@@ -1,3 +1,9 @@
+2018-05-15  Jason Merrill  <jason@redhat.com>
+
+       PR c++/64372 - CWG 1560, gratuitous lvalue-rvalue conversion in ?:
+       * call.c (build_conditional_expr_1): Don't force_rvalue when one arm
+       is a throw-expression.
+
 2018-05-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * cp-tree.h (DECL_MAYBE_IN_CHARGE_CDTOR_P): New.
index f620c0d..09a3618 100644 (file)
@@ -4969,56 +4969,33 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
   arg3_type = unlowered_expr_type (arg3);
   if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
     {
-      /* Do the conversions.  We don't these for `void' type arguments
-        since it can't have any effect and since decay_conversion
-        does not handle that case gracefully.  */
-      if (!VOID_TYPE_P (arg2_type))
-       arg2 = decay_conversion (arg2, complain);
-      if (!VOID_TYPE_P (arg3_type))
-       arg3 = decay_conversion (arg3, complain);
-      arg2_type = TREE_TYPE (arg2);
-      arg3_type = TREE_TYPE (arg3);
-
       /* [expr.cond]
 
         One of the following shall hold:
 
         --The second or the third operand (but not both) is a
-          throw-expression (_except.throw_); the result is of the
-          type of the other and is an rvalue.
+          throw-expression (_except.throw_); the result is of the type
+          and value category of the other.
 
         --Both the second and the third operands have type void; the
-          result is of type void and is an rvalue.
-
-        We must avoid calling force_rvalue for expressions of type
-        "void" because it will complain that their value is being
-        used.  */
+          result is of type void and is a prvalue.  */
       if (TREE_CODE (arg2) == THROW_EXPR
          && TREE_CODE (arg3) != THROW_EXPR)
        {
-         if (!VOID_TYPE_P (arg3_type))
-           {
-             arg3 = force_rvalue (arg3, complain);
-             if (arg3 == error_mark_node)
-               return error_mark_node;
-           }
-         arg3_type = TREE_TYPE (arg3);
          result_type = arg3_type;
+         is_glvalue = glvalue_p (arg3);
        }
       else if (TREE_CODE (arg2) != THROW_EXPR
               && TREE_CODE (arg3) == THROW_EXPR)
        {
-         if (!VOID_TYPE_P (arg2_type))
-           {
-             arg2 = force_rvalue (arg2, complain);
-             if (arg2 == error_mark_node)
-               return error_mark_node;
-           }
-         arg2_type = TREE_TYPE (arg2);
          result_type = arg2_type;
+         is_glvalue = glvalue_p (arg2);
        }
       else if (VOID_TYPE_P (arg2_type) && VOID_TYPE_P (arg3_type))
-       result_type = void_type_node;
+       {
+         result_type = void_type_node;
+         is_glvalue = false;
+       }
       else
        {
           if (complain & tf_error)
@@ -5037,7 +5014,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
          return error_mark_node;
        }
 
-      is_glvalue = false;
       goto valid_operands;
     }
   /* [expr.cond]
@@ -5155,10 +5131,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
       && same_type_p (arg2_type, arg3_type))
     {
       result_type = arg2_type;
-      if (processing_template_decl)
-       /* Let lvalue_kind know this was a glvalue.  */
-       result_type = cp_build_reference_type (result_type, xvalue_p (arg2));
-
       arg2 = mark_lvalue_use (arg2);
       arg3 = mark_lvalue_use (arg3);
       goto valid_operands;
@@ -5352,6 +5324,13 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
     return error_mark_node;
 
  valid_operands:
+  if (processing_template_decl && is_glvalue)
+    {
+      /* Let lvalue_kind know this was a glvalue.  */
+      tree arg = (result_type == arg2_type ? arg2 : arg3);
+      result_type = cp_build_reference_type (result_type, xvalue_p (arg));
+    }
+
   result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
 
   /* If the ARG2 and ARG3 are the same and don't have side-effects,
diff --git a/gcc/testsuite/g++.dg/cpp1y/dr1560.C b/gcc/testsuite/g++.dg/cpp1y/dr1560.C
new file mode 100644 (file)
index 0000000..b21ca98
--- /dev/null
@@ -0,0 +1,14 @@
+// Core 1560
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+  A();
+  A(const A&) = delete;
+};
+
+void f(bool b)
+{
+  A a;
+  b ? a : throw 42;
+}