if (anon)
return tree_cons (NULL_TREE, field, anon);
+
+ /* The Plan 9 compiler permits referring
+ directly to an anonymous struct/union field
+ using a typedef name. */
+ if (flag_plan9_extensions
+ && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+ && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
+ == TYPE_DECL)
+ && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+ == component))
+ break;
}
}
if (anon)
return tree_cons (NULL_TREE, field, anon);
+
+ /* The Plan 9 compiler permits referring directly to an
+ anonymous struct/union field using a typedef
+ name. */
+ if (flag_plan9_extensions
+ && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+ && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL
+ && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+ == component))
+ break;
}
if (DECL_NAME (field) == component)
if (!objc_is_public (datum, component))
return error_mark_node;
+ if (c_dialect_objc ()
+ && (ref = objc_build_getter_call (datum, component)))
+ return ref;
+
/* See if there is a field or component with name COMPONENT. */
if (code == RECORD_TYPE || code == UNION_TYPE)
arrays that are not lvalues (for example, members of structures returned
by functions).
+ For vector types, allow vector[i] but not i[vector], and create
+ *(((type*)&vectortype) + i) for the expression.
+
LOC is the location to use for the returned expression. */
tree
return error_mark_node;
if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE)
+ && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE
+ /* Allow vector[index] but not index[vector]. */
+ && TREE_CODE (TREE_TYPE (array)) != VECTOR_TYPE)
{
tree temp;
if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
{
- error_at (loc, "subscripted value is neither array nor pointer");
+ error_at (loc,
+ "subscripted value is neither array nor pointer nor vector");
+
return error_mark_node;
}
temp = array;
index = default_conversion (index);
gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+
+ /* For vector[index], convert the vector to a
+ pointer of the underlying type. */
+ if (TREE_CODE (TREE_TYPE (array)) == VECTOR_TYPE)
+ {
+ tree type = TREE_TYPE (array);
+ tree type1;
+
+ if (TREE_CODE (index) == INTEGER_CST)
+ if (!host_integerp (index, 1)
+ || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1)
+ >= TYPE_VECTOR_SUBPARTS (TREE_TYPE (array))))
+ warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
+
+ c_common_mark_addressable_vec (array);
+ type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+ type = build_pointer_type (type);
+ type1 = build_pointer_type (TREE_TYPE (array));
+ array = build1 (ADDR_EXPR, type1, array);
+ array = convert (type, array);
+ }
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
{
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- if (!lvalue_or_else (lhs, lv_assign))
+ /* For ObjC, defer this check until we have assessed CLASS.property. */
+ if (!c_dialect_objc () && !lvalue_or_else (lhs, lv_assign))
return error_mark_node;
if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
rhs_origtype = NULL_TREE;
}
+ if (c_dialect_objc ())
+ {
+ result = objc_build_setter_call (lhs, newrhs);
+ if (result)
+ return result;
+ if (!lvalue_or_else (lhs, lv_assign))
+ return error_mark_node;
+ }
+
/* Give an error for storing in something that is 'const'. */
if (TYPE_READONLY (lhstype)
return result;
}
\f
+/* Return whether STRUCT_TYPE has an anonymous field with type TYPE.
+ This is used to implement -fplan9-extensions. */
+
+static bool
+find_anonymous_field_with_type (tree struct_type, tree type)
+{
+ tree field;
+ bool found;
+
+ gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE
+ || TREE_CODE (struct_type) == UNION_TYPE);
+ found = false;
+ for (field = TYPE_FIELDS (struct_type);
+ field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) == NULL
+ && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ {
+ if (found)
+ return false;
+ found = true;
+ }
+ else if (DECL_NAME (field) == NULL
+ && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && find_anonymous_field_with_type (TREE_TYPE (field), type))
+ {
+ if (found)
+ return false;
+ found = true;
+ }
+ }
+ return found;
+}
+
+/* RHS is an expression whose type is pointer to struct. If there is
+ an anonymous field in RHS with type TYPE, then return a pointer to
+ that field in RHS. This is used with -fplan9-extensions. This
+ returns NULL if no conversion could be found. */
+
+static tree
+convert_to_anonymous_field (location_t location, tree type, tree rhs)
+{
+ tree rhs_struct_type, lhs_main_type;
+ tree field, found_field;
+ bool found_sub_field;
+ tree ret;
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs)));
+ rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs));
+ gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE
+ || TREE_CODE (rhs_struct_type) == UNION_TYPE);
+
+ gcc_assert (POINTER_TYPE_P (type));
+ lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+
+ found_field = NULL_TREE;
+ found_sub_field = false;
+ for (field = TYPE_FIELDS (rhs_struct_type);
+ field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) != NULL_TREE
+ || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
+ && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
+ continue;
+ if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+ {
+ if (found_field != NULL_TREE)
+ return NULL_TREE;
+ found_field = field;
+ }
+ else if (find_anonymous_field_with_type (TREE_TYPE (field),
+ lhs_main_type))
+ {
+ if (found_field != NULL_TREE)
+ return NULL_TREE;
+ found_field = field;
+ found_sub_field = true;
+ }
+ }
+
+ if (found_field == NULL_TREE)
+ return NULL_TREE;
+
+ ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field),
+ build_fold_indirect_ref (rhs), found_field,
+ NULL_TREE);
+ ret = build_fold_addr_expr_loc (location, ret);
+
+ if (found_sub_field)
+ {
+ ret = convert_to_anonymous_field (location, type, ret);
+ gcc_assert (ret != NULL_TREE);
+ }
+
+ return ret;
+}
+
/* Convert value RHS to type TYPE as preparation for an assignment to
an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the
original type of RHS; this differs from TREE_TYPE (RHS) for enum
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
+ /* The Plan 9 compiler permits a pointer to a struct to be
+ automatically converted into a pointer to an anonymous field
+ within the struct. */
+ if (flag_plan9_extensions
+ && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE)
+ && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE)
+ && mvl != mvr)
+ {
+ tree new_rhs = convert_to_anonymous_field (location, type, rhs);
+ if (new_rhs != NULL_TREE)
+ {
+ rhs = new_rhs;
+ rhstype = TREE_TYPE (rhs);
+ coder = TREE_CODE (rhstype);
+ ttr = TREE_TYPE (rhstype);
+ mvr = TYPE_MAIN_VARIANT (ttr);
+ }
+ }
+
/* C++ does not allow the implicit conversion void* -> T*. However,
for the purpose of reducing the number of false positives, we
tolerate the special case of
precision. */
bool may_need_excess_precision;
+ /* True means this is a boolean operation that converts both its
+ operands to truth-values. */
+ bool boolean_op = false;
+
if (location == UNKNOWN_LOCATION)
location = input_location;
op0 = c_common_truthvalue_conversion (location, op0);
op1 = c_common_truthvalue_conversion (location, op1);
converted = 1;
+ boolean_op = true;
}
if (code == TRUTH_ANDIF_EXPR)
{
if (build_type == NULL_TREE)
{
build_type = result_type;
- if (type0 != orig_type0 || type1 != orig_type1)
+ if ((type0 != orig_type0 || type1 != orig_type1)
+ && !boolean_op)
{
gcc_assert (may_need_excess_precision && common);
semantic_result_type = c_common_type (orig_type0, orig_type1);