Hi! This patch fixes ICEs if a non-lvalue vector (say cast of one vector to another vector type) was subscripted and used as lhs. The following patch, if *vecp is not lvalue, will copy it to a temporary variable which can be made addressable for the subscription, and afterwards wrap it into a NON_LVALUE_EXPR so that it is properly rejected if later used on the lhs.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2014-11-20 Jakub Jelinek <ja...@redhat.com> PR target/63764 c-family/ * c-common.h (convert_vector_to_pointer_for_subscript): Change return type to bool. * c-common.c: Include gimple-expr.c. (convert_vector_to_pointer_for_subscript): Change return type to bool. If *vecp is not lvalue_p and has VECTOR_TYPE, return true and copy it into a TARGET_EXPR and use that instead of *vecp directly. c/ * c-typeck.c (build_array_ref): Adjust convert_vector_to_pointer_for_subscript caller. If it returns true, call non_lvalue_loc on the result. cp/ * typeck.c (cp_build_array_ref): Adjust convert_vector_to_pointer_for_subscript caller. If it returns true, call non_lvalue_loc on the result. testsuite/ * c-c++-common/pr63764-1.c: New test. * c-c++-common/pr63764-2.c: New test. --- gcc/c-family/c-common.h.jj 2014-11-19 15:39:26.606065628 +0100 +++ gcc/c-family/c-common.h 2014-11-20 08:38:02.527655971 +0100 @@ -1310,7 +1310,7 @@ extern tree build_userdef_literal (tree enum overflow_type overflow, tree num_string); -extern void convert_vector_to_pointer_for_subscript (location_t, tree*, tree); +extern bool convert_vector_to_pointer_for_subscript (location_t, tree *, tree); /* Possibe cases of scalar_to_vector conversion. */ enum stv_conv { --- gcc/c-family/c-common.c.jj 2014-11-19 15:39:26.606065628 +0100 +++ gcc/c-family/c-common.c 2014-11-20 08:50:21.000573676 +0100 @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. #include "target-def.h" #include "gimplify.h" #include "wide-int-print.h" +#include "gimple-expr.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -12030,22 +12031,47 @@ build_userdef_literal (tree suffix_id, t } /* For vector[index], convert the vector to a - pointer of the underlying type. */ -void + pointer of the underlying type. Return true if the resulting + ARRAY_REF should not be an lvalue. */ + +bool convert_vector_to_pointer_for_subscript (location_t loc, - tree* vecp, tree index) + tree *vecp, tree index) { + bool ret = false; if (TREE_CODE (TREE_TYPE (*vecp)) == VECTOR_TYPE) { tree type = TREE_TYPE (*vecp); tree type1; + ret = !lvalue_p (*vecp); if (TREE_CODE (index) == INTEGER_CST) if (!tree_fits_uhwi_p (index) || tree_to_uhwi (index) >= TYPE_VECTOR_SUBPARTS (type)) warning_at (loc, OPT_Warray_bounds, "index value is out of bound"); - c_common_mark_addressable_vec (*vecp); + if (ret) + { + tree tmp = create_tmp_var_raw (type, NULL); + DECL_SOURCE_LOCATION (tmp) = loc; + *vecp = c_save_expr (*vecp); + if (TREE_CODE (*vecp) == C_MAYBE_CONST_EXPR) + { + bool non_const = C_MAYBE_CONST_EXPR_NON_CONST (*vecp); + *vecp = C_MAYBE_CONST_EXPR_EXPR (*vecp); + *vecp + = c_wrap_maybe_const (build4 (TARGET_EXPR, type, tmp, + *vecp, NULL_TREE, NULL_TREE), + non_const); + } + else + *vecp = build4 (TARGET_EXPR, type, tmp, *vecp, + NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (*vecp, loc); + c_common_mark_addressable_vec (tmp); + } + else + c_common_mark_addressable_vec (*vecp); type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type)); type1 = build_pointer_type (TREE_TYPE (*vecp)); bool ref_all = TYPE_REF_CAN_ALIAS_ALL (type1); @@ -12065,6 +12091,7 @@ convert_vector_to_pointer_for_subscript *vecp = build1 (ADDR_EXPR, type1, *vecp); *vecp = convert (type, *vecp); } + return ret; } /* Determine which of the operands, if any, is a scalar that needs to be --- gcc/c/c-typeck.c.jj 2014-11-19 15:39:24.044113650 +0100 +++ gcc/c/c-typeck.c 2014-11-20 08:38:02.534655847 +0100 @@ -2495,7 +2495,8 @@ build_array_ref (location_t loc, tree ar gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE); - convert_vector_to_pointer_for_subscript (loc, &array, index); + bool non_lvalue + = convert_vector_to_pointer_for_subscript (loc, &array, index); if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) { @@ -2557,6 +2558,8 @@ build_array_ref (location_t loc, tree ar | TREE_THIS_VOLATILE (array)); ret = require_complete_type (rval); protected_set_expr_location (ret, loc); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); return ret; } else @@ -2569,9 +2572,12 @@ build_array_ref (location_t loc, tree ar gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE); gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE); - return build_indirect_ref - (loc, build_binary_op (loc, PLUS_EXPR, ar, index, 0), - RO_ARRAY_INDEXING); + ret = build_indirect_ref (loc, build_binary_op (loc, PLUS_EXPR, ar, + index, 0), + RO_ARRAY_INDEXING); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); + return ret; } } --- gcc/cp/typeck.c.jj 2014-11-20 08:32:14.913826919 +0100 +++ gcc/cp/typeck.c 2014-11-20 08:38:02.536655812 +0100 @@ -3072,7 +3072,8 @@ cp_build_array_ref (location_t loc, tree break; } - convert_vector_to_pointer_for_subscript (loc, &array, idx); + bool non_lvalue + = convert_vector_to_pointer_for_subscript (loc, &array, idx); if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) { @@ -3155,6 +3156,8 @@ cp_build_array_ref (location_t loc, tree ret = require_complete_type_sfinae (fold_if_not_in_template (rval), complain); protected_set_expr_location (ret, loc); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); return ret; } @@ -3194,6 +3197,8 @@ cp_build_array_ref (location_t loc, tree RO_ARRAY_INDEXING, complain); protected_set_expr_location (ret, loc); + if (non_lvalue) + ret = non_lvalue_loc (loc, ret); return ret; } } --- gcc/testsuite/c-c++-common/pr63764-1.c.jj 2014-11-20 08:38:02.537655794 +0100 +++ gcc/testsuite/c-c++-common/pr63764-1.c 2014-11-20 08:38:02.537655794 +0100 @@ -0,0 +1,21 @@ +/* PR target/63764 */ +/* { dg-do compile } */ + +#define A __attribute__((vector_size (4 * sizeof (float)))) +typedef float V A; + +void +fn1 (V *x) +{ + V a = *x; + ((V) a)[0] = 0; /* { dg-error "lvalue required as left operand of assignment" } */ + *x = a; +} + +void +fn2 (V *x) +{ + float A a = *x; + ((float A) a)[0] = 0; /* { dg-error "lvalue required as left operand of assignment" } */ + *x = a; +} --- gcc/testsuite/c-c++-common/pr63764-2.c.jj 2014-11-20 08:38:02.537655794 +0100 +++ gcc/testsuite/c-c++-common/pr63764-2.c 2014-11-20 08:38:02.537655794 +0100 @@ -0,0 +1,35 @@ +/* PR target/63764 */ +/* { dg-do compile } */ + +#define A __attribute__((vector_size (4 * sizeof (float)))) +typedef float V A; + +float +fn1 (V *x) +{ + V a = *x; + return ((V) a)[0]; +} + +float +fn2 (V *x) +{ + float A a = *x; + return ((float A) a)[0]; +} + +void +fn3 (V *x) +{ + V a = *x; + a[0] = 0; + *x = a; +} + +void +fn4 (V *x) +{ + float A a = *x; + a[0] = 0; + *x = a; +} Jakub