https://gcc.gnu.org/g:c0f9055e6401ba50af69988e7455df520faa708f

commit c0f9055e6401ba50af69988e7455df520faa708f
Author: Mikael Morin <[email protected]>
Date:   Tue Feb 11 21:34:11 2025 +0100

    gimplify: reject non_lvalue as assignment lhs [PR122521]
    
    Regression tested on TODO.
    
    -- >8 --
    
    The previous patch made fortran array descriptor getters return references
    wrapped in a non_lvalue.  The goal was to reject their usage on the left of
    an assignment, but they are actually accepted by gimplification which just
    unwraps the non_lvalue.
    
    This change rejects usage of some cases of non-lvalues on the left hand side
    of an assignment, making the invalid API usage more visible.  Some cases
    are still accepted, especially conversions of lvalues, because the compiler
    documentation claims them to be supported, and the fortran frontend can
    generate them in some cases (by unluck rather than by design).  There is
    also the obscure case of a view_convert wrapped in a non_lvalue that is
    accepted to prevent testsuite failures:
      FAIL: g++.target/powerpc/altivec-cell-1.C (test for excess errors)
      FAIL: g++.target/powerpc/altivec-cell-4.C (test for excess errors)
    for generated code that looks like this:
      NLVE <VCE <short int[8]>(TARGET_EXPR <D.4160, a>)[b & 7]> = (short int) b
    where NLVE stands for NON_LVALUE_EXPR and VCE for VIEW_CONVERT_EXPR.
    
            PR fortran/122521
    
    gcc/ChangeLog:
    
            * fold-const.cc (maybe_lvalue_p): Make non-static.
            * fold-const.h (maybe_lvalue_p): New declaration.
            * gimplify.cc (is_modifiable_expr): New helper function.
            (gimplify_modify_expr): Throw an error if the left hand side is
            a non_lvalue.

Diff:
---
 gcc/fold-const.cc |  2 +-
 gcc/fold-const.h  |  1 +
 gcc/gimplify.cc   | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 1d0ed62a82fe..e27cbdd50397 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -2689,7 +2689,7 @@ fold_convert_loc (location_t loc, tree type, tree arg)
 /* Return false if expr can be assumed not to be an lvalue, true
    otherwise.  */
 
-static bool
+bool
 maybe_lvalue_p (const_tree x)
 {
   /* We only need to wrap lvalue tree codes.  */
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 8c0c3edba178..fbf2d6a76168 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -96,6 +96,7 @@ extern bool fold_convertible_p (const_tree, const_tree);
 #define fold_convert(T1,T2)\
    fold_convert_loc (UNKNOWN_LOCATION, T1, T2)
 extern tree fold_convert_loc (location_t, tree, tree);
+extern bool maybe_lvalue_p (const_tree);
 extern tree fold_ignored_result (tree);
 extern tree fold_abs_const (tree, tree);
 extern tree fold_indirect_ref_1 (location_t, tree, tree);
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 6c5d182ffab2..f23b4bddd9ba 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -7201,6 +7201,35 @@ gimplify_modify_expr_complex_part (tree *expr_p, 
gimple_seq *pre_p,
   return GS_ALL_DONE;
 }
 
+
+/* Return true if EXPR is a data reference that can be used on the left hand
+   side of an assignment.  */
+
+static bool
+is_modifiable_expr (tree expr)
+{
+  if (maybe_lvalue_p (expr))
+    return true;
+
+  /* Conversions are not lvalues according to the C standard, but gcc accepts
+     them as extension.  */
+  if (TREE_CODE (expr) == NOP_EXPR)
+    return is_modifiable_expr (TREE_OPERAND (expr, 0));
+
+  /* We can generate a NON_LVALUE_EXPR to represent an array reference of a
+     vector.  See PR63764.  */
+  if (TREE_CODE (expr) == NON_LVALUE_EXPR)
+    {
+      tree op0 = TREE_OPERAND (expr, 0);
+      return (TREE_CODE (op0) == ARRAY_REF
+             && TREE_CODE (TREE_OPERAND (op0, 0)) == VIEW_CONVERT_EXPR
+             && is_modifiable_expr (TREE_OPERAND (TREE_OPERAND (op0, 0), 0)));
+    }
+
+  return false;
+}
+
+
 /* Gimplify the MODIFY_EXPR node pointed to by EXPR_P.
 
       modify_expr
@@ -7233,6 +7262,12 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, 
gimple_seq *post_p,
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
              || TREE_CODE (*expr_p) == INIT_EXPR);
 
+  if (!is_modifiable_expr (*to_p))
+    {
+      error ("non-lvalue used as lhs in %qD", *expr_p);
+      return GS_ERROR;
+    }
+
   /* Trying to simplify a clobber using normal logic doesn't work,
      so handle it here.  */
   if (TREE_CLOBBER_P (*from_p))

Reply via email to