From: Mikael Morin <[email protected]>

Tested on aarch64-unknown-linux-gnu with languages:
ada,c,c++,fortran,go,objc,objc-c++

There is one regression with objc:
    …/gcc/testsuite/objc.dg/foreach-7.m:48:3: error: non-lvalue used as lhs in 
'object_function() = 0'
   'obj_type_ref' not supported by expression)(object, (const struct 
objc_selector *)&_OBJC_SELECTOR_TABLE[1]) = 
0…/gcc/testsuite/objc.dg/foreach-7.m:51:3: error: non-lvalue used as lhs in ''

If configured with modula2, the patch causes a bootstrap failure because
of errors alike to this:
    ../../../../src1/libgm2/libm2log/../../gcc/m2/gm2-libs-log/Strings.mod: In 
function ‘m2log_Strings_Ass
    ign’:
    
../../../../src1/libgm2/libm2log/../../gcc/m2/gm2-libs-log/Strings.mod:39:1: 
error: non-lvalue used as
    lhs in ‘__builtin_memcpy (__builtin_alloca (source._m2_high_1 + 1) = 
__builtin_alloca (source._m2_hig
    h_1 + 1), (PROC *) source._m2_contents, source._m2_high_1 + 1) = 
__builtin_memcpy (__builtin_alloca (s
    ource._m2_high_1 + 1) = __builtin_alloca (source._m2_high_1 + 1), (PROC *) 
source._m2_contents, source
    ._m2_high_1 + 1)’
       39 | BEGIN
          | ^~~~~

-- >8 --

The previous patch made fortran array descriptor getters return references
wrapped in a non_lvalue.  The goal was to more explicitly disallow any usage
on the left of an assignment, but such usage has remained actually accepted
by gimplification which just unwraps the non_lvalue.

This change makes those invalid usage rejected before the non_lvalue is
unwrapped, making the invalid API usage more visible.  Some non-lvalue cases
are still accepted, mainly conversions of lvalues, because the compiler
documentation claims them to be supported, and the fortran frontend can
generate them in some cases (even if not really on purpose).  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
        not lvalue-like.
---
 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 b4e3a56aeb5..1fec633dc58 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 25e1cbf911f..299bb1b6c91 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 223b55b7e93..fd03725dc54 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 %qE", *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))
-- 
2.53.0

Reply via email to