aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-typeck.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-typeck.c')
-rw-r--r--gcc/c/c-typeck.c401
1 files changed, 370 insertions, 31 deletions
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index b6b45558a54..4cd52d36ac3 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "tree-inline.h"
#include "omp-low.h"
+#include "c-upc.h"
+#include "c-upc-low.h"
#include "c-family/c-objc.h"
#include "c-family/c-ubsan.h"
#include "cilk.h"
@@ -91,6 +93,7 @@ static tree lookup_field (tree, tree);
static int convert_arguments (location_t, vec<location_t>, tree,
vec<tree, va_gc> *, vec<tree, va_gc> *, tree,
tree);
+static tree c_pointer_int_sum (location_t, enum tree_code, tree, tree);
static tree pointer_diff (location_t, tree, tree);
static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
enum impl_conv, bool, tree, tree, int);
@@ -317,9 +320,12 @@ addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common)
static tree
qualify_type (tree type, tree like)
{
+ tree result_type;
addr_space_t as_type = TYPE_ADDR_SPACE (type);
addr_space_t as_like = TYPE_ADDR_SPACE (like);
addr_space_t as_common;
+ int result_quals;
+ tree result_block_factor = NULL_TREE;
/* If the two named address spaces are different, determine the common
superset address space. If there isn't one, raise an error. */
@@ -330,10 +336,31 @@ qualify_type (tree type, tree like)
type, like);
}
- return c_build_qualified_type (type,
- TYPE_QUALS_NO_ADDR_SPACE (type)
- | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
- | ENCODE_QUAL_ADDR_SPACE (as_common));
+ result_quals = TYPE_QUALS_NO_ADDR_SPACE (type)
+ | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
+ | ENCODE_QUAL_ADDR_SPACE (as_common);
+
+ if (result_quals & TYPE_QUAL_SHARED)
+ {
+ tree b1 = TYPE_BLOCK_FACTOR (type);
+ tree b2 = TYPE_BLOCK_FACTOR (like);
+ /* We can merge in a new UPC blocking factor only
+ if one/other is NULL. Otherwise, they must match. */
+ if (b1 != b2)
+ {
+ if (b1 && !b2)
+ result_block_factor = b1;
+ else if (!b1 && b2)
+ result_block_factor = b2;
+ else
+ gcc_unreachable ();
+ }
+ }
+
+ result_type = c_build_qualified_type (type, result_quals,
+ result_block_factor);
+
+ return result_type;
}
/* Return true iff the given tree T is a variable length array. */
@@ -626,6 +653,7 @@ common_pointer_type (tree t1, tree t2)
tree pointed_to_2, mv2;
tree target;
unsigned target_quals;
+ tree target_block_factor = NULL_TREE;
addr_space_t as1, as2, as_common;
int quals1, quals2;
@@ -668,6 +696,10 @@ common_pointer_type (tree t1, tree t2)
else
target_quals = (quals1 | quals2);
+ if (target_quals & TYPE_QUAL_SHARED)
+ target_block_factor = TYPE_BLOCK_FACTOR (
+ strip_array_types (pointed_to_1));
+
/* If the two named address spaces are different, determine the common
superset address space. This is guaranteed to exist due to the
assumption that comp_target_type returned non-zero. */
@@ -677,8 +709,9 @@ common_pointer_type (tree t1, tree t2)
gcc_unreachable ();
target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+ t2 = c_build_qualified_type (target, target_quals, target_block_factor);
- t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
+ t1 = build_pointer_type (t2);
return build_type_attribute_variant (t1, attributes);
}
@@ -1086,6 +1119,13 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
if (TYPE_QUALS (t1) != TYPE_QUALS (t2))
return 0;
+ /* If the type is UPC qualified, the block sizes have
+ to be equal. The block sizes are either NULL
+ or are the same integer constant. */
+ if ((TYPE_QUALS (t1) & TYPE_QUAL_SHARED)
+ && (TYPE_BLOCK_FACTOR (t1) != TYPE_BLOCK_FACTOR (t2)))
+ return 0;
+
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
qualifiers (just above). */
@@ -2096,6 +2136,10 @@ default_conversion (tree exp)
/* Functions and arrays have been converted during parsing. */
gcc_assert (code != FUNCTION_TYPE);
+
+ if (code == ARRAY_TYPE && SHARED_TYPE_P (type))
+ return array_to_pointer_conversion (input_location, exp);
+
if (code == ARRAY_TYPE)
return exp;
@@ -2350,6 +2394,7 @@ build_component_ref (location_t loc, tree datum, tree component)
error_at (loc, "%qT has no member named %qE", type, component);
return error_mark_node;
}
+ gcc_assert (!TREE_SHARED (field));
/* Accessing elements of atomic structures or unions is undefined
behavior (C11 6.5.2.3#5). */
@@ -2371,6 +2416,8 @@ build_component_ref (location_t loc, tree datum, tree component)
do
{
tree subdatum = TREE_VALUE (field);
+ tree sub_elem_type = strip_array_types (TREE_TYPE (subdatum));
+ tree upc_block_factor = NULL_TREE;
int quals;
tree subtype;
bool use_datum_quals;
@@ -2385,10 +2432,15 @@ build_component_ref (location_t loc, tree datum, tree component)
use_datum_quals = (datum_lvalue
|| TREE_CODE (TREE_TYPE (subdatum)) != ARRAY_TYPE);
- quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
+ quals = TYPE_QUALS (sub_elem_type);
if (use_datum_quals)
quals |= TYPE_QUALS (TREE_TYPE (datum));
- subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
+ /* All references to UPC shared struct components
+ are defined to have an indefinite (zero) blocking factor. */
+ if (quals & TYPE_QUAL_SHARED)
+ upc_block_factor = size_zero_node;
+ subtype = c_build_qualified_type (TREE_TYPE (subdatum),
+ quals, upc_block_factor);
ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
NULL_TREE);
@@ -2399,6 +2451,8 @@ build_component_ref (location_t loc, tree datum, tree component)
if (TREE_THIS_VOLATILE (subdatum)
|| (use_datum_quals && TREE_THIS_VOLATILE (datum)))
TREE_THIS_VOLATILE (ref) = 1;
+ if (TREE_SHARED (datum))
+ TREE_SHARED (ref) = 1;
if (TREE_DEPRECATED (subdatum))
warn_deprecated_use (subdatum, NULL_TREE);
@@ -2496,6 +2550,7 @@ build_indirect_ref (location_t loc, tree ptr, ref_operator errstring)
TREE_SIDE_EFFECTS (ref)
= TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+ TREE_SHARED (ref) = SHARED_TYPE_P (t);
protected_set_expr_location (ref, loc);
return ref;
}
@@ -2584,7 +2639,8 @@ build_array_ref (location_t loc, tree array, tree index)
bool non_lvalue
= convert_vector_to_pointer_for_subscript (loc, &array, index);
- if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
+ && !SHARED_TYPE_P (TREE_TYPE (array)))
{
tree rval, type;
@@ -3644,6 +3700,23 @@ parser_build_binary_op (location_t location, enum tree_code code,
return result;
}
+/* Return a tree for the sum or difference (RESULTCODE says which)
+ of pointer PTROP and integer INTOP. */
+
+static
+tree
+c_pointer_int_sum (location_t location, enum tree_code resultcode,
+ tree ptrop, tree intop)
+{
+ /* The result is a pointer of the same type that is being added. */
+ tree result_type = TREE_TYPE (ptrop);
+
+ if (SHARED_TYPE_P (TREE_TYPE (result_type)))
+ return upc_pts_int_sum (location, resultcode, ptrop, intop);
+
+ return pointer_int_sum (location, resultcode, ptrop, intop);
+}
+
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
@@ -3656,6 +3729,7 @@ pointer_diff (location_t loc, tree op0, tree op1)
addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
tree target_type = TREE_TYPE (TREE_TYPE (op0));
+ tree subtrahend_type = TREE_TYPE (TREE_TYPE (op1));
tree orig_op1 = op1;
/* If the operands point into different address spaces, we need to
@@ -3692,6 +3766,9 @@ pointer_diff (location_t loc, tree op0, tree op1)
pedwarn (loc, OPT_Wpointer_arith,
"pointer to a function used in subtraction");
+ if (SHARED_TYPE_P (target_type) || SHARED_TYPE_P (subtrahend_type))
+ return upc_pts_diff (op0, op1);
+
/* First do the subtraction as integers;
then drop through to build the divide operator.
Do not do default conversions on the minus operator
@@ -4293,6 +4370,11 @@ build_unary_op (location_t location,
"wrong type argument to decrement");
}
+ /* UPC pointer-to-shared types cannot be
+ incremented/decremented directly. */
+ if (SHARED_TYPE_P (TREE_TYPE (argtype)))
+ return upc_pts_increment (location, code, arg);
+
inc = c_size_in_bytes (TREE_TYPE (argtype));
inc = convert_to_ptrofftype_loc (location, inc);
}
@@ -4507,6 +4589,10 @@ build_unary_op (location_t location,
ret = build1 (code, argtype, arg);
return_build_unary_op:
gcc_assert (ret != error_mark_node);
+ /* The result of an operation on objects that
+ are UPC shared qualified, must not be shared qualified. */
+ if (SHARED_TYPE_P (TREE_TYPE (ret)))
+ TREE_TYPE (ret) = build_unshared_type (TREE_TYPE (ret));
if (TREE_CODE (ret) == INTEGER_CST && !TREE_OVERFLOW (ret)
&& !(TREE_CODE (xarg) == INTEGER_CST && !TREE_OVERFLOW (xarg)))
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
@@ -4950,7 +5036,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
"pointer/integer type mismatch in conditional expression");
else
{
- op2 = null_pointer_node;
+ op2 = !SHARED_TYPE_P (TREE_TYPE (type1))
+ ? null_pointer_node : upc_null_pts_node;
}
result_type = type1;
}
@@ -4961,7 +5048,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
"pointer/integer type mismatch in conditional expression");
else
{
- op1 = null_pointer_node;
+ op1 = !SHARED_TYPE_P (TREE_TYPE (type2))
+ ? null_pointer_node : upc_null_pts_node;
}
result_type = type2;
}
@@ -5256,6 +5344,12 @@ build_c_cast (location_t loc, tree type, tree expr)
if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr)))
return build1 (NOP_EXPR, type, expr);
+ if (SHARED_TYPE_P (type))
+ {
+ error_at (loc, "UPC does not allow casts to a shared type");
+ return error_mark_node;
+ }
+
type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE)
@@ -5277,6 +5371,22 @@ build_c_cast (location_t loc, tree type, tree expr)
return error_mark_node;
}
+ if (integer_zerop (value)
+ && POINTER_TYPE_P (type)
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && POINTER_TYPE_P (TREE_TYPE (expr))
+ && ! SHARED_TYPE_P (TREE_TYPE (TREE_TYPE (expr))))
+ {
+ value = upc_null_pts_node;
+ }
+
+ if (!SHARED_TYPE_P (type) && SHARED_TYPE_P (TREE_TYPE (expr)))
+ {
+ /* UPC disallows things like:
+ (int)p = <expr>; (where p is a shared int) */
+ value = non_lvalue (value);
+ }
+
if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
{
if (RECORD_OR_UNION_TYPE_P (type))
@@ -5327,6 +5437,17 @@ build_c_cast (location_t loc, tree type, tree expr)
otype = TREE_TYPE (value);
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE)
+ {
+ int t_shared = SHARED_TYPE_P (TREE_TYPE (type));
+ int o_shared = SHARED_TYPE_P (TREE_TYPE (otype));
+ if ((!t_shared && o_shared)
+ || (t_shared && o_shared
+ && !lang_hooks.types_compatible_p (type, otype)))
+ return build1 (CONVERT_EXPR, type, value);
+ }
+
/* Optionally warn about potentially worrisome casts. */
if (warn_cast_qual
&& TREE_CODE (type) == POINTER_TYPE
@@ -5377,6 +5498,33 @@ build_c_cast (location_t loc, tree type, tree expr)
warning_at (loc, OPT_Wcast_align,
"cast increases required alignment of target type");
+ if (POINTER_TYPE_P (type)
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && POINTER_TYPE_P (otype)
+ && !SHARED_TYPE_P (TREE_TYPE (otype)))
+ {
+ error_at (loc, "UPC does not allow casts from a local pointer to a pointer-to-shared");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == INTEGER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (type))
+ && !integer_zerop (value))
+ {
+ error_at (loc, "UPC does not allow casts from an integer to a pointer-to-shared");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && SHARED_TYPE_P (TREE_TYPE (otype)))
+ {
+ /* UPC pointer-to-shared -> integer
+ This will be lowered by the genericize pass. */
+ return build1 (CONVERT_EXPR, type, value);
+ }
+
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
@@ -5699,6 +5847,12 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
newrhs = c_fully_fold (newrhs, false, NULL);
if (rhs_semantic_type)
newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+ /* If the lhs is UPC 'shared' qualified, we drop the qualifier
+ for the purposes of conversions from rhstype to lhstype.
+ This will prevent the inadvertent creation of temporaries
+ with "shared" asserted. */
+ if (SHARED_TYPE_P (lhstype))
+ lhstype = build_unshared_type (lhstype);
newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs,
rhs_origtype, ic_assign, npc,
NULL_TREE, NULL_TREE, 0);
@@ -6012,6 +6166,34 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
} \
} while (0)
+ /* Similar to WARN_FOR_ASSIGNMENT, but used to diagnose certain
+ error conditions defined by the UPC language specification
+ when converting between pointer-to-shared types and other types. */
+#define ERROR_FOR_ASSIGNMENT(LOCATION, OPT, AR, AS, IN, RE) \
+ do { \
+ switch (errtype) \
+ { \
+ case ic_argpass: \
+ error_at (LOCATION, AR, parmnum, rname); \
+ inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
+ ? DECL_SOURCE_LOCATION (fundecl) : LOCATION, \
+ "expected %qT but argument is of type %qT", \
+ type, rhstype); \
+ break; \
+ case ic_assign: \
+ error_at (LOCATION, AS); \
+ break; \
+ case ic_init: \
+ error_at (LOCATION, IN); \
+ break; \
+ case ic_return: \
+ error_at (LOCATION, RE); \
+ break; \
+ default: \
+ gcc_unreachable (); \
+ } \
+ } while (0)
+
/* This macro is used to emit diagnostics to ensure that all format
strings are complete sentences, visible to gettext and checked at
compile time. It is the same as PEDWARN_FOR_ASSIGNMENT but with an
@@ -6255,7 +6437,9 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
/* Can convert integer zero to any pointer type. */
if (null_pointer_constant)
{
- rhs = null_pointer_node;
+ tree ttl = TREE_TYPE (memb_type);
+ rhs = !SHARED_TYPE_P (ttl)
+ ? null_pointer_node : upc_null_pts_node;
break;
}
}
@@ -6345,6 +6529,43 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr),
TYPE_QUAL_ATOMIC)
: TYPE_MAIN_VARIANT (mvr));
+ if ((SHARED_TYPE_P (ttl) && !SHARED_TYPE_P (ttr))
+ && !integer_zerop (rhs))
+ {
+ error_at (location, "UPC does not allow assignments from a local pointer "
+ "to a pointer-to-shared");
+ return error_mark_node;
+ }
+ if (!SHARED_TYPE_P (ttl) && SHARED_TYPE_P (ttr))
+ {
+ if (upc_is_null_pts_p (rhs))
+ {
+ return null_pointer_node;
+ }
+ else
+ {
+ error_at (location, "UPC does not allow assignments "
+ "from a pointer-to-shared to a local pointer");
+ return error_mark_node;
+ }
+ }
+ if (SHARED_TYPE_P (ttl) && SHARED_TYPE_P (ttr) && (ttl != ttr)
+ && !(VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)))
+ {
+ const tree bs_l = get_block_factor (ttl);
+ const tree bs_r = get_block_factor (ttr);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_l, bs_r))
+ {
+ error_at (location, "UPC does not allow assignment "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
+
/* Opaque pointers are treated like void pointers. */
is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
@@ -6583,6 +6804,19 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
}
else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
{
+ if (!null_pointer_constant && SHARED_TYPE_P (TREE_TYPE (type)))
+ {
+ ERROR_FOR_ASSIGNMENT (location, 0,
+ G_("passing argument %d of %qE attempts to make "
+ "a UPC pointer-to-shared value from an integer"),
+ G_("assignment attempts to make a UPC pointer-to-shared "
+ "value from an integer"),
+ G_("initialization attempts to make a UPC pointer-to-shared "
+ "value from an integer without a cast"),
+ G_("return makes a UPC pointer-to-shared value from an "
+ "integer"));
+ return error_mark_node;
+ }
/* An explicit constant 0 can convert to a pointer,
or one that results from arithmetic, even including
a cast to integer type. */
@@ -6688,21 +6922,31 @@ valid_compound_expr_initializer (tree value, tree endtype)
void
store_init_value (location_t init_loc, tree decl, tree init, tree origtype)
{
- tree value, type;
- bool npc = false;
+ const bool npc = init && null_pointer_constant_p (init);
+ const bool is_upc_decl_init = upc_check_decl_init (decl, init);
+ const bool require_constant = TREE_STATIC (decl) && !is_upc_decl_init;
+ tree type = TREE_TYPE (decl);
+ tree value;
/* If variable's type was invalidly declared, just ignore it. */
- type = TREE_TYPE (decl);
if (TREE_CODE (type) == ERROR_MARK)
return;
/* Digest the specified initializer into an expression. */
- if (init)
- npc = null_pointer_constant_p (init);
value = digest_init (init_loc, type, init, origtype, npc,
- true, TREE_STATIC (decl));
+ true, require_constant);
+
+ /* UPC cannot initialize certain values at compile time.
+ For example, the address of a UPC 'shared' variable must
+ be evaluated at runtime. */
+
+ if (is_upc_decl_init)
+ {
+ upc_decl_init (decl, value);
+ return;
+ }
/* Store the expression if valid; else report error. */
@@ -7508,6 +7752,9 @@ really_start_incremental_init (tree type)
designator_depth = 0;
designator_erroneous = 0;
+ /* The result of the constructor must not be UPC shared qualified */
+ if (SHARED_TYPE_P (constructor_type))
+ constructor_type = build_unshared_type (constructor_type);
if (RECORD_OR_UNION_TYPE_P (constructor_type))
{
constructor_fields = TYPE_FIELDS (constructor_type);
@@ -9793,6 +10040,20 @@ c_finish_return (location_t loc, tree retval, tree origtype)
TREE_NO_WARNING (ret_stmt) |= no_warning;
return add_stmt (ret_stmt);
}
+
+/* Convert EXPR to TYPE if the type of EXPR is
+ assignment compatible with TYPE.
+ Otherwise, issue an error (or warning) as appropriate. */
+
+tree
+c_cvt_expr_for_assign (location_t loc, tree type, tree expr)
+{
+ if (expr == NULL_TREE || expr == error_mark_node)
+ return expr;
+ return convert_for_assignment (loc, UNKNOWN_LOCATION, type,
+ expr, TREE_TYPE (expr),
+ ic_assign, false, NULL_TREE, NULL_TREE, 0);
+}
struct c_switch {
/* The SWITCH_EXPR being built. */
@@ -10736,12 +10997,12 @@ build_binary_op (location_t location, enum tree_code code,
/* Handle the pointer + int case. */
if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
+ ret = c_pointer_int_sum (location, PLUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
+ ret = c_pointer_int_sum (location, PLUS_EXPR, op1, op0);
goto return_build_binary_op;
}
else
@@ -10760,7 +11021,7 @@ build_binary_op (location_t location, enum tree_code code,
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
+ ret = c_pointer_int_sum (location, MINUS_EXPR, op0, op1);
goto return_build_binary_op;
}
else
@@ -11116,6 +11377,33 @@ build_binary_op (location_t location, enum tree_code code,
addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
addr_space_t as_common = ADDR_SPACE_GENERIC;
+ if ((SHARED_TYPE_P (tt0)
+ && !(SHARED_TYPE_P (tt1) || integer_zerop(op1)))
+ || (SHARED_TYPE_P (tt1)
+ && !(SHARED_TYPE_P (tt0) || integer_zerop(op0))))
+ {
+ error_at (location, "UPC does not allow comparisons "
+ "between pointers to shared and "
+ "local pointers");
+ return error_mark_node;
+ }
+ if (SHARED_TYPE_P (tt0)
+ && SHARED_TYPE_P (tt1) && (tt0 != tt1)
+ && !(VOID_TYPE_P (tt0) || VOID_TYPE_P (tt1)))
+ {
+ const tree bs_0 = get_block_factor (tt0);
+ const tree bs_1 = get_block_factor (tt1);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_0, bs_1))
+ {
+ error_at (location, "UPC does not allow comparison "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
@@ -11147,9 +11435,17 @@ build_binary_op (location_t location, enum tree_code code,
if (result_type == NULL_TREE)
{
- int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
- result_type = build_pointer_type
- (build_qualified_type (void_type_node, qual));
+ if (SHARED_TYPE_P(tt0) || SHARED_TYPE_P(tt1))
+ {
+ result_type = upc_pts_type_node;
+ }
+ else
+ {
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node,
+ qual));
+ }
}
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
@@ -11221,10 +11517,35 @@ build_binary_op (location_t location, enum tree_code code,
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
- addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+ const tree tt0 = TREE_TYPE (type0);
+ const tree tt1 = TREE_TYPE (type1);
+ addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
+ addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
addr_space_t as_common;
+ if (SHARED_TYPE_P (tt0) != SHARED_TYPE_P (tt1))
+ {
+ error_at (location, "UPC does not allow comparisons between "
+ "pointers to shared and local pointers");
+ return error_mark_node;
+ }
+ if (SHARED_TYPE_P (tt0)
+ && SHARED_TYPE_P (tt1) && (tt0 != tt1)
+ && !(VOID_TYPE_P (tt0) || VOID_TYPE_P (tt1)))
+ {
+ const tree bs_0 = get_block_factor (tt0);
+ const tree bs_1 = get_block_factor (tt1);
+ /* Both source and destination are non-void pointers to shared,
+ whose target types are not equal.
+ UPC dictates that their blocking factors must be equal. */
+ if (!tree_int_cst_equal (bs_0, bs_1))
+ {
+ error_at (location, "UPC does not allow comparison "
+ "between pointers to shared with "
+ "differing block sizes without a cast");
+ return error_mark_node;
+ }
+ }
if (comp_target_types (location, type0, type1))
{
result_type = common_pointer_type (type0, type1);
@@ -11247,6 +11568,11 @@ build_binary_op (location_t location, enum tree_code code,
"disjoint address spaces");
return error_mark_node;
}
+ else if (SHARED_TYPE_P (TREE_TYPE (type0))
+ || SHARED_TYPE_P (TREE_TYPE (type1)))
+ {
+ result_type = upc_pts_type_node;
+ }
else
{
int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
@@ -13461,10 +13787,16 @@ c_finish_transaction (location_t loc, tree block, int flags)
NULL, then it should be used as the qualified type
ORIG_QUAL_INDIRECT levels down in array type derivation (to
preserve information about the typedef name from which an array
- type was derived). */
+ type was derived).
+
+ LAYOUT_QUALIFIER is the UPC "blocking factor". It is an integral
+ constant that specifies the size of the blocks that will be
+ distributed across threads. It is NULL, when not compiling UPC. */
tree
-c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
+c_build_qualified_type (tree type, int type_quals,
+ tree layout_qualifier,
+ tree orig_qual_type,
size_t orig_qual_indirect)
{
if (type == error_mark_node)
@@ -13474,7 +13806,9 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
{
tree t;
tree element_type = c_build_qualified_type (TREE_TYPE (type),
- type_quals, orig_qual_type,
+ type_quals,
+ layout_qualifier,
+ orig_qual_type,
orig_qual_indirect - 1);
/* See if we already have an identically qualified type. */
@@ -13483,7 +13817,10 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
else
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
{
- if (TYPE_QUALS (strip_array_types (t)) == type_quals
+ const tree t_elem_type = strip_array_types (t);
+ tree t_elem_block_factor = TYPE_BLOCK_FACTOR (t_elem_type);
+ if (TYPE_QUALS (t_elem_type) == type_quals
+ && t_elem_block_factor == layout_qualifier
&& TYPE_NAME (t) == TYPE_NAME (type)
&& TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
&& attribute_list_equal (TYPE_ATTRIBUTES (t),
@@ -13514,7 +13851,8 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
TYPE_REVERSE_STORAGE_ORDER (unqualified_canon) = 1;
}
TYPE_CANONICAL (t)
- = c_build_qualified_type (unqualified_canon, type_quals);
+ = c_build_qualified_type (unqualified_canon, type_quals,
+ layout_qualifier);
}
else
TYPE_CANONICAL (t) = t;
@@ -13535,7 +13873,8 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
tree var_type = (orig_qual_type && orig_qual_indirect == 0
? orig_qual_type
- : build_qualified_type (type, type_quals));
+ : build_qualified_type (type, type_quals,
+ layout_qualifier));
/* A variant type does not inherit the list of incomplete vars from the
type main variant. */
if (RECORD_OR_UNION_TYPE_P (var_type)