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))
