On 2/4/21 6:09 PM, Marek Polacek wrote:
On Thu, Feb 04, 2021 at 03:47:54PM -0500, Jason Merrill via Gcc-patches wrote:
On 2/4/21 1:11 PM, Marek Polacek wrote:
On Thu, Feb 04, 2021 at 10:59:21AM -0500, Jason Merrill wrote:
On 2/3/21 7:03 PM, Marek Polacek wrote:
Since most of volatile is deprecated in C++20, we are required to warn
for compound assignments to volatile variables and so on.  But here we
have

     volatile int x, y, z;
     (b ? x : y) = 1;

and we shouldn't warn, because simple assignments like x = 24; should
not provoke the warning when they are a discarded-value expression.

We warn here because when ?: is used as an lvalue, we transform it in
cp_build_modify_expr/COND_EXPR from (a ? b : c) = rhs to

     (a ? (b = rhs) : (c = rhs))

and build_conditional_expr then calls mark_lvalue_use for the new
artificial assignments

Hmm, that seems wrong; the ?: expression itself does not use lvalue operands
any more than ',' does.  I notice that removing those mark_lvalue_use calls
doesn't regress Wunused-var-10.c, which was added with them in r160289.

The mark_lvalue_use calls didn't strike me as wrong because [expr.cond]/7
says that lvalue-to-rvalue conversion is performed on the second and third
operands.

Only after we've decided (in /6) that the result is a prvalue.

Oh, I see.  :~

With those mark_lvalue_use calls removed, we'd not issue the
warning for

    (b ? (x = 2) : y) = 1;
    (b ? x : (y = 5)) = 1;

Why wouldn't we?  The assignment should call mark_lvalue_use for the LHS,
which recursively applies it to the arms of the ?:.

Aha: we call mark_lvalue_use_*nonread* and the warning was guarded by
read_p.  I don't know why I did it, I see no regressions if I just
remove the check.  And then I get the expected results.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?

OK.

-- >8 --
Since most of volatile is deprecated in C++20, we are required to warn
for compound assignments to volatile variables and so on.  But here we
have

   volatile int x, y, z;
   (b ? x : y) = 1;

and we shouldn't warn, because simple assignments like x = 24; should
not provoke the warning when they are a discarded-value expression.

We warn here because when ?: is used as an lvalue, we transform it in
cp_build_modify_expr/COND_EXPR from (a ? b : c) = rhs to

   (a ? (b = rhs) : (c = rhs))

and build_conditional_expr then calls mark_lvalue_use for the new
artificial assignments, which then evokes the warning.  The calls
to mark_lvalue_use were added in r160289 to suppress warnings in
Wunused-var-10.c, but looks like they're no longer needed.

To warn on

     (b ? (x = 2) : y) = 1;
     (b ? x : (y = 5)) = 1;

I've tweaked a check in mark_use/MODIFY_EXPR.

I'd argue this is a regression because GCC 9 doesn't warn.

gcc/cp/ChangeLog:

        PR c++/98947
        * call.c (build_conditional_expr_1): Don't call mark_lvalue_use
        on arg2/arg3.
        * expr.c (mark_use) <case MODIFY_EXPR>: Don't check read_p when
        issuing the -Wvolatile warning.  Only set TREE_THIS_VOLATILE if
        a warning was emitted.

gcc/testsuite/ChangeLog:

        PR c++/98947
        * g++.dg/cpp2a/volatile5.C: New test.
---
  gcc/cp/call.c                          |  2 --
  gcc/cp/expr.c                          | 14 +++++++-------
  gcc/testsuite/g++.dg/cpp2a/volatile5.C | 15 +++++++++++++++
  3 files changed, 22 insertions(+), 9 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/volatile5.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c7e13f3a22b..4744c9768ec 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5559,8 +5559,6 @@ build_conditional_expr_1 (const op_location_t &loc,
        && same_type_p (arg2_type, arg3_type))
      {
        result_type = arg2_type;
-      arg2 = mark_lvalue_use (arg2);
-      arg3 = mark_lvalue_use (arg3);
        goto valid_operands;
      }
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index 480e740f08c..d16d1896f2d 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -224,17 +224,17 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
             a volatile-qualified type is deprecated unless the assignment
             is either a discarded-value expression or appears in an
             unevaluated context."  */
-         if (read_p
-             && !cp_unevaluated_operand
+         if (!cp_unevaluated_operand
              && (TREE_THIS_VOLATILE (lhs)
                  || CP_TYPE_VOLATILE_P (TREE_TYPE (lhs)))
              && !TREE_THIS_VOLATILE (expr))
            {
-             warning_at (location_of (expr), OPT_Wvolatile,
-                         "using value of simple assignment with %<volatile%>-"
-                         "qualified left operand is deprecated");
-             /* Make sure not to warn about this assignment again.  */
-             TREE_THIS_VOLATILE (expr) = true;
+             if (warning_at (location_of (expr), OPT_Wvolatile,
+                             "using value of simple assignment with "
+                             "%<volatile%>-qualified left operand is "
+                             "deprecated"))
+               /* Make sure not to warn about this assignment again.  */
+               TREE_THIS_VOLATILE (expr) = true;
            }
          break;
        }
diff --git a/gcc/testsuite/g++.dg/cpp2a/volatile5.C 
b/gcc/testsuite/g++.dg/cpp2a/volatile5.C
new file mode 100644
index 00000000000..1f9d23845b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/volatile5.C
@@ -0,0 +1,15 @@
+// PR c++/98947
+// { dg-do compile }
+
+volatile int x, y, z;
+
+void
+f (bool b)
+{
+  (b ? x : y) = 1;
+  (b ? x : y) += 1; // { dg-warning "compound assignment" "" { target c++20 } }
+  z = (b ? x : y) = 1; // { dg-warning "using value of simple assignment" "" { 
target c++20 } }
+  ((z = 2) ? x : y) = 1; // { dg-warning "using value of simple assignment" "" 
{ target c++20 } }
+  (b ? (x = 2) : y) = 1; // { dg-warning "using value of simple assignment" "" 
{ target c++20 } }
+  (b ? x : (y = 5)) = 1; // { dg-warning "using value of simple assignment" "" 
{ target c++20 } }
+}

base-commit: 4e7c24d97dd65083a770252ce942f43d408fe11d


Reply via email to