summaryrefslogtreecommitdiff
path: root/gcc/c-typeck.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r--gcc/c-typeck.c311
1 files changed, 254 insertions, 57 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 4c55e587de3..9b1f09c4593 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -284,14 +284,55 @@ c_type_promotes_to (tree type)
return type;
}
+/* Return true if between two named address spaces, whether there is a superset
+ named address space that encompasses both address spaces. If there is a
+ superset, return which address space is the superset. */
+
+static bool
+addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common)
+{
+ if (as1 == as2)
+ {
+ *common = as1;
+ return true;
+ }
+ else if (targetm.addr_space.subset_p (as1, as2))
+ {
+ *common = as2;
+ return true;
+ }
+ else if (targetm.addr_space.subset_p (as2, as1))
+ {
+ *common = as1;
+ return true;
+ }
+ else
+ return false;
+}
+
/* Return a variant of TYPE which has all the type qualifiers of LIKE
as well as those of TYPE. */
static tree
qualify_type (tree type, tree like)
{
+ addr_space_t as_type = TYPE_ADDR_SPACE (type);
+ addr_space_t as_like = TYPE_ADDR_SPACE (like);
+ addr_space_t as_common;
+
+ /* If the two named address spaces are different, determine the common
+ superset address space. If there isn't one, raise an error. */
+ if (!addr_space_superset (as_type, as_like, &as_common))
+ {
+ as_common = as_type;
+ error ("%qT and %qT are in disjoint named address spaces",
+ type, like);
+ }
+
return c_build_qualified_type (type,
- TYPE_QUALS (type) | TYPE_QUALS (like));
+ TYPE_QUALS_NO_ADDR_SPACE (type)
+ | TYPE_QUALS_NO_ADDR_SPACE (like)
+ | ENCODE_QUAL_ADDR_SPACE (as_common));
}
/* Return true iff the given tree T is a variable length array. */
@@ -371,7 +412,8 @@ composite_type (tree t1, tree t2)
bool t1_complete, t2_complete;
/* We should not have any type quals on arrays at all. */
- gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
+ gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1)
+ && !TYPE_QUALS_NO_ADDR_SPACE (t2));
t1_complete = COMPLETE_TYPE_P (t1);
t2_complete = COMPLETE_TYPE_P (t2);
@@ -585,6 +627,8 @@ common_pointer_type (tree t1, tree t2)
tree pointed_to_2, mv2;
tree target;
unsigned target_quals;
+ addr_space_t as1, as2, as_common;
+ int quals1, quals2;
/* Save time if the two types are the same. */
@@ -616,10 +660,24 @@ common_pointer_type (tree t1, tree t2)
/* For function types do not merge const qualifiers, but drop them
if used inconsistently. The middle-end uses these to mark const
and noreturn functions. */
+ quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
+ quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
+
if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
- target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2);
+ target_quals = (quals1 & quals2);
else
- target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2);
+ target_quals = (quals1 | quals2);
+
+ /* 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. */
+ as1 = TYPE_ADDR_SPACE (pointed_to_1);
+ as2 = TYPE_ADDR_SPACE (pointed_to_2);
+ if (!addr_space_superset (as1, as2, &as_common))
+ gcc_unreachable ();
+
+ target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+
t1 = build_pointer_type (c_build_qualified_type (target, target_quals));
return build_type_attribute_variant (t1, attributes);
}
@@ -1103,20 +1161,28 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p)
return attrval == 2 && val == 1 ? 2 : val;
}
-/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers. */
+/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring
+ their qualifiers, except for named address spaces. If the pointers point to
+ different named addresses, then we must determine if one address space is a
+ subset of the other. */
static int
comp_target_types (location_t location, tree ttl, tree ttr)
{
int val;
- tree mvl, mvr;
+ tree mvl = TREE_TYPE (ttl);
+ tree mvr = TREE_TYPE (ttr);
+ addr_space_t asl = TYPE_ADDR_SPACE (mvl);
+ addr_space_t asr = TYPE_ADDR_SPACE (mvr);
+ addr_space_t as_common;
bool enum_and_int_p;
+ /* Fail if pointers point to incompatible address spaces. */
+ if (!addr_space_superset (asl, asr, &as_common))
+ return 0;
+
/* Do not lose qualifiers on element types of array types that are
pointer targets by taking their TYPE_MAIN_VARIANT. */
- mvl = TREE_TYPE (ttl);
- mvr = TREE_TYPE (ttr);
if (TREE_CODE (mvl) != ARRAY_TYPE)
mvl = TYPE_MAIN_VARIANT (mvl);
if (TREE_CODE (mvr) != ARRAY_TYPE)
@@ -2673,6 +2739,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values,
{
tree typetail, val;
unsigned int parmnum;
+ bool error_args = false;
const bool type_generic = fundecl
&& lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl)));
bool type_generic_remove_excess_precision = false;
@@ -2942,6 +3009,8 @@ convert_arguments (tree typelist, VEC(tree,gc) *values,
parmval = default_conversion (val);
VEC_replace (tree, values, parmnum, parmval);
+ if (parmval == error_mark_node)
+ error_args = true;
if (typetail)
typetail = TREE_CHAIN (typetail);
@@ -2955,7 +3024,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values,
return -1;
}
- return parmnum;
+ return error_args ? -1 : (int) parmnum;
}
/* This is the entry point used by the parser to build unary operators
@@ -3063,11 +3132,43 @@ static tree
pointer_diff (location_t loc, tree op0, tree op1)
{
tree restype = ptrdiff_type_node;
+ tree result, inttype;
+ 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 con0, con1, lit0, lit1;
tree orig_op1 = op1;
+ /* If the operands point into different address spaces, we need to
+ explicitly convert them to pointers into the common address space
+ before we can subtract the numerical address values. */
+ if (as0 != as1)
+ {
+ addr_space_t as_common;
+ tree common_type;
+
+ /* Determine the common superset address space. This is guaranteed
+ to exist because the caller verified that comp_target_types
+ returned non-zero. */
+ if (!addr_space_superset (as0, as1, &as_common))
+ gcc_unreachable ();
+
+ common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1));
+ op0 = convert (common_type, op0);
+ op1 = convert (common_type, op1);
+ }
+
+ /* Determine integer type to perform computations in. This will usually
+ be the same as the result type (ptrdiff_t), but may need to be a wider
+ type if pointers for the address space are wider than ptrdiff_t. */
+ if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0)))
+ inttype = lang_hooks.types.type_for_size
+ (TYPE_PRECISION (TREE_TYPE (op0)), 0);
+ else
+ inttype = restype;
+
+
if (TREE_CODE (target_type) == VOID_TYPE)
pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
"pointer of type %<void *%> used in subtraction");
@@ -3125,8 +3226,8 @@ pointer_diff (location_t loc, tree op0, tree op1)
in case restype is a short type. */
op0 = build_binary_op (loc,
- MINUS_EXPR, convert (restype, op0),
- convert (restype, op1), 0);
+ MINUS_EXPR, convert (inttype, op0),
+ convert (inttype, op1), 0);
/* This generates an error if op1 is pointer to incomplete type. */
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
error_at (loc, "arithmetic on pointer to an incomplete type");
@@ -3135,8 +3236,11 @@ pointer_diff (location_t loc, tree op0, tree op1)
op1 = c_size_in_bytes (target_type);
/* Divide by the size, in easiest possible way. */
- return fold_build2_loc (loc, EXACT_DIV_EXPR, restype,
- op0, convert (restype, op1));
+ result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype,
+ op0, convert (inttype, op1));
+
+ /* Convert to final result type if necessary. */
+ return convert (restype, result);
}
/* Construct and perhaps optimize a tree representation
@@ -3940,17 +4044,9 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
"conditional expression"));
}
if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
- {
- op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
- NULL, op1);
- C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
- }
+ op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST)
- {
- op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2),
- NULL, op2);
- C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const;
- }
+ op2 = c_wrap_maybe_const (op2, !op2_maybe_const);
}
}
}
@@ -3964,12 +4060,22 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
}
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
+ addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+ addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2));
+ addr_space_t as_common;
+
if (comp_target_types (colon_loc, type1, type2))
result_type = common_pointer_type (type1, type2);
else if (null_pointer_constant_p (orig_op1))
- result_type = qualify_type (type2, type1);
+ result_type = type2;
else if (null_pointer_constant_p (orig_op2))
- result_type = qualify_type (type1, type2);
+ result_type = type1;
+ else if (!addr_space_superset (as1, as2, &as_common))
+ {
+ error_at (colon_loc, "pointers to disjoint address spaces "
+ "used in conditional expression");
+ return error_mark_node;
+ }
else if (VOID_TYPE_P (TREE_TYPE (type1)))
{
if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
@@ -3990,10 +4096,13 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
}
else
{
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+
if (!objc_ok)
pedwarn (colon_loc, 0,
"pointer type mismatch in conditional expression");
- result_type = build_pointer_type (void_type_node);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
@@ -4152,7 +4261,8 @@ build_compound_expr (location_t loc, tree expr1, tree expr2)
/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to
which we are casting. OTYPE is the type of the expression being
cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared
- on the command line. */
+ on the command line. Named address space qualifiers are not handled
+ here, because they result in different warnings. */
static void
handle_warn_cast_qual (tree type, tree otype)
@@ -4178,9 +4288,11 @@ handle_warn_cast_qual (tree type, tree otype)
taken away. */
if (TREE_CODE (in_otype) == FUNCTION_TYPE
&& TREE_CODE (in_type) == FUNCTION_TYPE)
- added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+ added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
else
- discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+ discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));
}
while (TREE_CODE (in_type) == POINTER_TYPE
&& TREE_CODE (in_otype) == POINTER_TYPE);
@@ -4329,6 +4441,36 @@ build_c_cast (location_t loc, tree type, tree expr)
&& TREE_CODE (otype) == POINTER_TYPE)
handle_warn_cast_qual (type, otype);
+ /* Warn about conversions between pointers to disjoint
+ address spaces. */
+ if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && !null_pointer_constant_p (value))
+ {
+ addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+ addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype));
+ addr_space_t as_common;
+
+ if (!addr_space_superset (as_to, as_from, &as_common))
+ {
+ if (ADDR_SPACE_GENERIC_P (as_from))
+ warning_at (loc, 0, "cast to %s address space pointer "
+ "from disjoint generic address space pointer",
+ c_addr_space_name (as_to));
+
+ else if (ADDR_SPACE_GENERIC_P (as_to))
+ warning_at (loc, 0, "cast to generic address space pointer "
+ "from disjoint %s address space pointer",
+ c_addr_space_name (as_from));
+
+ else
+ warning_at (loc, 0, "cast to %s address space pointer "
+ "from disjoint %s address space pointer",
+ c_addr_space_name (as_to),
+ c_addr_space_name (as_from));
+ }
+ }
+
/* Warn about possible alignment problems. */
if (STRICT_ALIGNMENT
&& TREE_CODE (type) == POINTER_TYPE
@@ -4923,7 +5065,8 @@ convert_for_assignment (location_t location, tree type, tree rhs,
certain things, it is okay to use a const or volatile
function where an ordinary one is wanted, but not
vice-versa. */
- if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
WARN_FOR_ASSIGNMENT (location, 0,
G_("passing argument %d of %qE "
"makes qualified function "
@@ -4937,7 +5080,8 @@ convert_for_assignment (location_t location, tree type, tree rhs,
G_("return makes qualified function "
"pointer from unqualified"));
}
- else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+ else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
WARN_FOR_ASSIGNMENT (location, 0,
G_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
@@ -4970,6 +5114,8 @@ convert_for_assignment (location_t location, tree type, tree rhs,
tree mvr = ttr;
bool is_opaque_pointer;
int target_cmp = 0; /* Cache comp_target_types () result. */
+ addr_space_t asl;
+ addr_space_t asr;
if (TREE_CODE (mvl) != ARRAY_TYPE)
mvl = TYPE_MAIN_VARIANT (mvl);
@@ -4990,6 +5136,36 @@ convert_for_assignment (location_t location, tree type, tree rhs,
"request for implicit conversion "
"from %qT to %qT not permitted in C++", rhstype, type);
+ /* See if the pointers point to incompatible address spaces. */
+ asl = TYPE_ADDR_SPACE (ttl);
+ asr = TYPE_ADDR_SPACE (ttr);
+ if (!null_pointer_constant_p (rhs)
+ && asr != asl && !targetm.addr_space.subset_p (asr, asl))
+ {
+ switch (errtype)
+ {
+ case ic_argpass:
+ error_at (location, "passing argument %d of %qE from pointer to "
+ "non-enclosed address space", parmnum, rname);
+ break;
+ case ic_assign:
+ error_at (location, "assignment from pointer to "
+ "non-enclosed address space");
+ break;
+ case ic_init:
+ error_at (location, "initialization from pointer to "
+ "non-enclosed address space");
+ break;
+ case ic_return:
+ error_at (location, "return from pointer to "
+ "non-enclosed address space");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return error_mark_node;
+ }
+
/* Check if the right-hand side has a format attribute but the
left-hand side doesn't. */
if (warn_missing_format_attribute
@@ -5053,7 +5229,8 @@ convert_for_assignment (location_t location, tree type, tree rhs,
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
- if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
{
/* Types differing only by the presence of the 'volatile'
qualifier are acceptable if the 'volatile' has been added
@@ -5093,7 +5270,8 @@ convert_for_assignment (location_t location, tree type, tree rhs,
that say the function will not do certain things,
it is okay to use a const or volatile function
where an ordinary one is wanted, but not vice-versa. */
- if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
+ if (TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
WARN_FOR_ASSIGNMENT (location, 0,
G_("passing argument %d of %qE makes "
"qualified function pointer "
@@ -8661,16 +8839,17 @@ c_finish_stmt_expr (location_t loc, tree body)
goto continue_searching;
}
+ if (last == error_mark_node)
+ return last;
+
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
- if (last == error_mark_node
- || (last == BIND_EXPR_BODY (body)
- && BIND_EXPR_VARS (body) == NULL))
+ if (last == BIND_EXPR_BODY (body)
+ && BIND_EXPR_VARS (body) == NULL)
{
/* Even if this looks constant, do not allow it in a constant
expression. */
- last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last);
- C_MAYBE_CONST_EXPR_NON_CONST (last) = 1;
+ last = c_wrap_maybe_const (last, true);
/* Do not warn if the return value of a statement expression is
unused. */
TREE_NO_WARNING (last) = 1;
@@ -9200,24 +9379,34 @@ build_binary_op (location_t location, enum tree_code code,
{
tree tt0 = TREE_TYPE (type0);
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 = ADDR_SPACE_GENERIC;
+
/* Anything compares with void *. void * compares with anything.
Otherwise, the targets must be compatible
and both must be object or both incomplete. */
if (comp_target_types (location, type0, type1))
result_type = common_pointer_type (type0, type1);
+ else if (null_pointer_constant_p (orig_op0))
+ result_type = type1;
+ else if (null_pointer_constant_p (orig_op1))
+ result_type = type0;
+ else if (!addr_space_superset (as0, as1, &as_common))
+ {
+ error_at (location, "comparison of pointers to "
+ "disjoint address spaces");
+ return error_mark_node;
+ }
else if (VOID_TYPE_P (tt0))
{
- /* op0 != orig_op0 detects the case of something
- whose value is 0 but which isn't a valid null ptr const. */
- if (pedantic && !null_pointer_constant_p (orig_op0)
- && TREE_CODE (tt1) == FUNCTION_TYPE)
+ if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"comparison of %<void *%> with function pointer");
}
else if (VOID_TYPE_P (tt1))
{
- if (pedantic && !null_pointer_constant_p (orig_op1)
- && TREE_CODE (tt0) == FUNCTION_TYPE)
+ if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
pedwarn (location, OPT_pedantic, "ISO C forbids "
"comparison of %<void *%> with function pointer");
}
@@ -9228,7 +9417,11 @@ build_binary_op (location_t location, enum tree_code code,
"comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
- result_type = ptr_type_node;
+ {
+ 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 && null_pointer_constant_p (orig_op1))
{
@@ -9272,6 +9465,10 @@ 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));
+ addr_space_t as_common;
+
if (comp_target_types (location, type0, type1))
{
result_type = common_pointer_type (type0, type1);
@@ -9283,9 +9480,17 @@ build_binary_op (location_t location, enum tree_code code,
pedwarn (location, OPT_pedantic, "ISO C forbids "
"ordered comparisons of pointers to functions");
}
+ else if (!addr_space_superset (as0, as1, &as_common))
+ {
+ error_at (location, "comparison of pointers to "
+ "disjoint address spaces");
+ return error_mark_node;
+ }
else
{
- result_type = ptr_type_node;
+ int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ result_type = build_pointer_type
+ (build_qualified_type (void_type_node, qual));
pedwarn (location, 0,
"comparison of distinct pointer types lacks a cast");
}
@@ -9545,17 +9750,9 @@ build_binary_op (location_t location, enum tree_code code,
if (!in_late_binary_op)
{
if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST)
- {
- op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0),
- NULL, op0);
- C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const;
- }
+ op0 = c_wrap_maybe_const (op0, !op0_maybe_const);
if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST)
- {
- op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1),
- NULL, op1);
- C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const;
- }
+ op1 = c_wrap_maybe_const (op1, !op1_maybe_const);
}
}
}