On 4/24/25 3:50 AM, Jakub Jelinek wrote:
Hi!

The -Wunused-but-set-* warnings work by using 2 bits on VAR_DECLs &
PARM_DECLs, TREE_USED and DECL_READ_P.  If neither is set, we typically
emit -Wunused-variable or -Wunused-parameter warning, that is for variables
which are just declared (including initializer) and completely unused.
If TREE_USED is set and DECL_READ_P is unset, -Wunused-but-set-* warnings
are emitted, i.e. for variables which can appear on the lhs of an assignment
expression but aren't actually used elsewhere.  The DECL_READ_P marking is
done through mark_exp_read called from lots of places (e.g. lvalue to rvalue
conversions etc.).

LLVM has an extension on top of that in that it doesn't count pre/post
inc/decrements as use (i.e. DECL_READ_P for GCC).

The following patch does that too, though because we had the current
behavior for 11+ years already and lot of people is -Wunused-but-set-*
warning free in the current GCC behavior and not in the clang one (including
GCC sources), it allows users to choose.
Furthermore, it implements another level, where also var @= expr uses of var
(except when it is also used in expr) aren't counted as DECL_READ_P.

I think it would be nice to also handle var = var @ expr or var = expr @ var
but unfortunately mark_exp_read is then done in both FEs during parsing of
var @ expr or expr @ var and the code doesn't know it is rhs of an
assignment with var as lhs.

The patch works mostly by checking if DECL_READ_P is clear at some point and
then clearing it again after some operation which might have set it.

-Wunused or -Wall or -Wunused -Wextra or -Wall -Wextra turn on the 3 level
of the new warning (i.e. the one which ignores also var++, ++var etc. as
well as var @= expr), so does -Wunused-but-set-{variable,parameter}, but
users can use explicit -Wunused-but-set-{variable,parameter}={1,2} to select
a different level.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

--- gcc/cp/cp-gimplify.cc.jj    2025-04-12 21:41:42.660924514 +0200
+++ gcc/cp/cp-gimplify.cc       2025-04-23 21:33:19.050931604 +0200
@@ -3200,7 +3200,23 @@ cp_fold (tree x, fold_flags_t flags)
loc = EXPR_LOCATION (x);
        op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops, flags);
+      bool clear_decl_read;
+      clear_decl_read = false;
+      if (code == MODIFY_EXPR
+         && (VAR_P (op0) || TREE_CODE (op0) == PARM_DECL)
+         && !DECL_READ_P (op0)
+         && (VAR_P (op0) ? warn_unused_but_set_variable
+                         : warn_unused_but_set_parameter) > 2
+         && BINARY_CLASS_P (TREE_OPERAND (x, 1))
+         && TREE_OPERAND (TREE_OPERAND (x, 1), 0) == op0)
+       {
+         mark_exp_read (TREE_OPERAND (TREE_OPERAND (x, 1), 1));
+         if (!DECL_READ_P (op0))
+           clear_decl_read = true;
+       }
        op1 = cp_fold_rvalue (TREE_OPERAND (x, 1), flags);
+      if (clear_decl_read)
+       DECL_READ_P (op0) = 0;

Why does this need to happen in cp_fold? Weren't the flags set properly at build time?

@@ -211,8 +211,27 @@ mark_use (tree expr, bool rvalue_p, bool
            }
          return expr;
        }
-      gcc_fallthrough();
+      gcc_fallthrough ();
      CASE_CONVERT:
+      if (VOID_TYPE_P (TREE_TYPE (expr)))
+       switch (TREE_CODE (TREE_OPERAND (expr, 0)))
+         {
+         case PREINCREMENT_EXPR:
+         case PREDECREMENT_EXPR:
+         case POSTINCREMENT_EXPR:
+         case POSTDECREMENT_EXPR:

Why is this specific to these codes? I would think we would want consistent handling of (void) here and in mark_exp_read.

@@ -3740,7 +3740,28 @@ finish_unary_op_expr (location_t op_loc,
    tree expr_ovl = expr;
if (!processing_template_decl)
-    expr_ovl = cp_fully_fold (expr_ovl);
+    switch (code)
+      {
+      case PREINCREMENT_EXPR:
+      case PREDECREMENT_EXPR:
+      case POSTINCREMENT_EXPR:
+      case POSTDECREMENT_EXPR:
+       tree stripped_expr;
+       stripped_expr = tree_strip_any_location_wrapper (expr);
+       if ((VAR_P (stripped_expr) || TREE_CODE (stripped_expr) == PARM_DECL)
+           && !DECL_READ_P (stripped_expr)
+           && (VAR_P (stripped_expr) ? warn_unused_but_set_variable
+                                     : warn_unused_but_set_parameter) > 1)
+         {
+           expr_ovl = cp_fully_fold (expr_ovl);

Again I wonder why cp_fold is setting DECL_READ_P.

Jason

Reply via email to