https://gcc.gnu.org/g:079c1670216c67d546b3735774717aa561a9ea86

commit 079c1670216c67d546b3735774717aa561a9ea86
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_lvalue on the left hand side
    of an assignment, making the invalid API usage more visible.  Not all cases
    are rejected because rejecting all of them causes 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:
      NLE <VCE <short int[8]>(TARGET_EXPR <D.4160, a>)[b & 7]> = (short int) b
    where NLE 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